From b0cf340079384703dbc8248ceb6537991b462886 Mon Sep 17 00:00:00 2001 From: russell Date: Wed, 29 May 2024 08:46:50 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BE=D1=82=D1=87=D0=B5=D1=82=D1=8B,=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=87=D1=82=D0=B0=20=D0=B8=20=D1=84=D0=B8=D0=BA=D1=81=20?= =?UTF-8?q?=D0=B1=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusinessLogics/ExcursionLogic.cs | 2 +- .../BusinessLogics/PlaceLogic.cs | 8 +- .../BusinessLogics/ReportLogic.cs | 136 ++++++++ .../MailWorker/AbstractMailWorker.cs | 49 +++ .../MailWorker/MailKitWorker.cs | 47 +++ .../OfficePackage/AbstractSaveToExcel.cs | 125 ++++++++ .../OfficePackage/AbstractSaveToPdf.cs | 77 +++++ .../OfficePackage/AbstractSaveToWord.cs | 90 ++++++ .../HelperEnums/ExcelStyleInfoType.cs | 11 + .../HelperEnums/PdfParagraphAlignmentType.cs | 11 + .../HelperEnums/WordJustificationType.cs | 9 + .../HelperModels/ExcelCellParameters.cs | 17 + .../OfficePackage/HelperModels/ExcelInfo.cs | 13 + .../HelperModels/ExcelMergeParameters.cs | 11 + .../OfficePackage/HelperModels/PdfInfo.cs | 17 + .../HelperModels/PdfParagraph.cs | 13 + .../HelperModels/PdfRowParameters.cs | 13 + .../OfficePackage/HelperModels/WordInfo.cs | 13 + .../HelperModels/WordParagraph.cs | 9 + .../HelperModels/WordTextProperties.cs | 13 + .../OfficePackage/Implements/SaveToExcel.cs | 292 ++++++++++++++++++ .../OfficePackage/Implements/SaveToPdf.cs | 114 +++++++ .../OfficePackage/Implements/SaveToWord.cs | 135 ++++++++ .../TravelAgencyBusinessLogic.csproj | 3 + .../BindingModels/ExcursionBindingModel.cs | 2 + .../BindingModels/MailConfigBindingModel.cs | 18 ++ .../BindingModels/MailSendInfoBindingModel.cs | 17 + .../BindingModels/PlaceBindingModel.cs | 2 - .../BindingModels/ReportBindingModel.cs | 15 + .../BusinessLogicsContracts/IReportLogic.cs | 16 + .../SearchModels/ExcursionSearchModel.cs | 2 + .../SearchModels/PlaceSearchModel.cs | 2 - .../SearchModels/TourSearchModel.cs | 4 + .../ViewModels/ExcursionViewModel.cs | 4 + .../ViewModels/PlaceViewModel.cs | 2 - .../ViewModels/ReportPlaceTourViewModel.cs | 8 - .../ViewModels/ReportTourPeriodViewModel.cs | 8 +- .../ViewModels/ReportTourPlaceViewModel.cs | 9 + .../Models/IExcursionModel.cs | 2 + .../Models/IPlaceModel.cs | 2 - .../Implements/ExcursionStorage.cs | 16 + .../Implements/PlaceStorage.cs | 13 - .../Implements/TourStorage.cs | 23 +- ... 20240529001818_InitialCreate.Designer.cs} | 35 +-- ...ate.cs => 20240529001818_InitialCreate.cs} | 92 +++--- .../TravelAgencyDatabaseModelSnapshot.cs | 33 +- .../Models/Excursion.cs | 17 +- .../Models/Place.cs | 14 +- .../Controllers/ExcursionController.cs | 22 +- .../Controllers/HomeController.cs | 178 ++++++++++- TravelAgency/TravelAgencyWebApp/Program.cs | 29 ++ .../TravelAgencyWebApp/SeedingService.cs | 109 +++++++ .../Views/Excursion/CreateExcursion.cshtml | 6 + .../Views/Excursion/Excursions.cshtml | 6 + .../Views/Excursion/UpdateExcursion.cshtml | 12 + .../Views/Home/ReportMenu.cshtml | 2 +- .../Views/Home/ReportPlaceTour.cshtml | 48 --- .../Views/Home/ReportTourPeriod.cshtml | 77 +++-- .../Views/Home/ReportTourPlace.cshtml | 51 +++ .../TravelAgencyWebApp/appsettings.json | 9 +- 60 files changed, 1882 insertions(+), 251 deletions(-) create mode 100644 TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ReportLogic.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/MailWorker/AbstractMailWorker.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/MailWorker/MailKitWorker.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToExcel.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToPdf.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToWord.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/WordJustificationType.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelCellParameters.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelInfo.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelMergeParameters.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfInfo.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordTextProperties.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToExcel.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToPdf.cs create mode 100644 TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToWord.cs create mode 100644 TravelAgency/TravelAgencyContracts/BindingModels/MailConfigBindingModel.cs create mode 100644 TravelAgency/TravelAgencyContracts/BindingModels/MailSendInfoBindingModel.cs create mode 100644 TravelAgency/TravelAgencyContracts/BindingModels/ReportBindingModel.cs create mode 100644 TravelAgency/TravelAgencyContracts/BusinessLogicsContracts/IReportLogic.cs delete mode 100644 TravelAgency/TravelAgencyContracts/ViewModels/ReportPlaceTourViewModel.cs create mode 100644 TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPlaceViewModel.cs rename TravelAgency/TravelAgencyDatabaseImplement/Migrations/{20240429175309_InitialCreate.Designer.cs => 20240529001818_InitialCreate.Designer.cs} (97%) rename TravelAgency/TravelAgencyDatabaseImplement/Migrations/{20240429175309_InitialCreate.cs => 20240529001818_InitialCreate.cs} (97%) create mode 100644 TravelAgency/TravelAgencyWebApp/SeedingService.cs delete mode 100644 TravelAgency/TravelAgencyWebApp/Views/Home/ReportPlaceTour.cshtml create mode 100644 TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPlace.cshtml diff --git a/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ExcursionLogic.cs b/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ExcursionLogic.cs index 5d94297..1c4245a 100644 --- a/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ExcursionLogic.cs +++ b/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ExcursionLogic.cs @@ -21,7 +21,7 @@ namespace TravelAgencyBusinessLogic.BusinessLogics public List? ReadList(ExcursionSearchModel? model) { - _logger.LogInformation("ReadList. Id: {Id}, ExcursionName: {ExcursionName}, UserId: {UserId}.", model?.Id, model?.ExcursionName, model?.UserId); + _logger.LogInformation("ReadList. Id: {Id}, ExcursionName: {ExcursionName}, UserId: {UserId}, PlaceId: {PlaceId}.", model?.Id, model?.ExcursionName, model?.UserId, model?.PlaceId); var list = (model == null) ? _excursionStorage.GetFullList() : _excursionStorage.GetFilteredList(model); if (list == null) { diff --git a/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/PlaceLogic.cs b/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/PlaceLogic.cs index 18cb1c9..c5478ba 100644 --- a/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/PlaceLogic.cs +++ b/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/PlaceLogic.cs @@ -21,7 +21,7 @@ namespace TravelAgencyBusinessLogic.BusinessLogics public List? ReadList(PlaceSearchModel? model) { - _logger.LogInformation("ReadList. Id: {Id}, PlaceName: {PlaceName}, ExcursionId: {ExcursionId}.", model?.Id, model?.PlaceName, model?.ExcursionId); + _logger.LogInformation("ReadList. Id: {Id}, PlaceName: {PlaceName}.", model?.Id, model?.PlaceName); var list = (model == null) ? _placeStorage.GetFullList() : _placeStorage.GetFilteredList(model); if (list == null) { @@ -101,11 +101,7 @@ namespace TravelAgencyBusinessLogic.BusinessLogics { throw new ArgumentNullException("Нет адреса места", nameof(model.PlaceAddress)); } - if (model.ExcursionId <= 0) - { - throw new ArgumentNullException("Некорректный идентификатор экскурсии", nameof(model.ExcursionId)); - } - _logger.LogInformation("Place. Id: {id}, PlaceName: {PlaceName}, PlaceAddress: {PlaceAddress}, ExcursionId: {ExcursionId}", model.Id, model.PlaceName, model.PlaceAddress, model.ExcursionId); + _logger.LogInformation("Place. Id: {id}, PlaceName: {PlaceName}, PlaceAddress: {PlaceAddress}", model.Id, model.PlaceName, model.PlaceAddress); var element = _placeStorage.GetElement(new PlaceSearchModel { PlaceName = model.PlaceName, diff --git a/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ReportLogic.cs b/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ReportLogic.cs new file mode 100644 index 0000000..2d32b04 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/BusinessLogics/ReportLogic.cs @@ -0,0 +1,136 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; +using TravelAgencyBusinessLogic.OfficePackage; +using TravelAgencyContracts.BindingModels; +using TravelAgencyContracts.BusinessLogicsContracts; +using TravelAgencyContracts.StoragesContracts; +using TravelAgencyContracts.ViewModels; +using TravelAgencyContracts.SearchModels; + +namespace TravelAgencyBusinessLogic.BusinessLogics +{ + public class ReportLogic : IReportLogic + { + private readonly ITourStorage _tourStorage; + + private readonly IPlaceStorage _placeStorage; + + private readonly IGuideStorage _guideStorage; + + private readonly IExcursionGroupStorage _excursionGroupStorage; + + private readonly IExcursionStorage _excursionStorage; + + private readonly AbstractSaveToWord _saveToWord; + + private readonly AbstractSaveToExcel _saveToExcel; + + private readonly AbstractSaveToPdf _saveToPdf; + + public ReportLogic(ITourStorage tourStorage, + IPlaceStorage placeStorage, + IGuideStorage guideStorage, + IExcursionGroupStorage excursionGroupStorage, + IExcursionStorage excursionStorage, + AbstractSaveToWord saveToWord, + AbstractSaveToExcel saveToExcel, + AbstractSaveToPdf saveToPdf) + { + _tourStorage = tourStorage; + _placeStorage = placeStorage; + _guideStorage = guideStorage; + _excursionGroupStorage = excursionGroupStorage; + _excursionStorage = excursionStorage; + + _saveToWord = saveToWord; + _saveToExcel = saveToExcel; + _saveToPdf = saveToPdf; + } + + public List GetTourPlaces(ReportBindingModel model) + { + var result = new List(); + + var excursions = _excursionStorage.GetFullList(); + + foreach (var tour in model.Tours) + { + var record = new ReportTourPlaceViewModel + { + Tour = _tourStorage.GetElement(new TourSearchModel{ Id = tour }), + Places = new HashSet() + }; + + foreach (var excursion in excursions) + { + if (excursion.ExcursionTours.ContainsKey(tour)) + { + var place = _placeStorage.GetElement(new PlaceSearchModel { Id = excursion.PlaceId }); + record.Places.Add(place); + } + } + + result.Add(record); + } + + return result; + } + + public List GetTourPeriod(ReportBindingModel model) + { + var result = new List(); + + var tours = _tourStorage.GetFilteredList(new TourSearchModel + { + UserId = model.UserId, + DateFrom = model.DateFrom, + DateTo = model.DateTo + }); + + var excursionGroups = _excursionGroupStorage.GetFullList(); + + foreach (var tour in tours) + { + var record = new ReportTourPeriodViewModel + { + Tour = tour, + ExcursionGroups = new HashSet(), + Guides = new HashSet(), + }; + + foreach (var excursionGroup in excursionGroups) + { + if (excursionGroup.ExcursionGroupTours.ContainsKey(tour.Id)) + { + record.ExcursionGroups.Add(excursionGroup); + var guide = _guideStorage.GetElement(new GuideSearchModel { Id = excursionGroup.GuideId }); + record.Guides.Add(guide); + } + } + + result.Add(record); + } + + return result; + } + + public void SaveTourPlacesToWordFile(ReportBindingModel model) + { + _saveToWord.CreateDoc(new WordInfo + { + FileName = model.FileName, + Title = "Список мест для посещения по выбранным турам.", + TourPlaces = GetTourPlaces(model) + }); + } + + public void SaveTourPlacesToExcelFile(ReportBindingModel model) + { + _saveToExcel.CreateReport(new ExcelInfo + { + FileName = model.FileName, + Title = "Список мест", + TourPlaces = GetTourPlaces(model) + }); + } + } +} diff --git a/TravelAgency/TravelAgencyBusinessLogic/MailWorker/AbstractMailWorker.cs b/TravelAgency/TravelAgencyBusinessLogic/MailWorker/AbstractMailWorker.cs new file mode 100644 index 0000000..6f7eef0 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/MailWorker/AbstractMailWorker.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Logging; +using TravelAgencyContracts.BindingModels; +using TravelAgencyContracts.BusinessLogicsContracts; + +namespace TravelAgencyBusinessLogic.MailWorker +{ + public abstract class AbstractMailWorker + { + protected string _mailLogin = string.Empty; + protected string _mailPassword = string.Empty; + protected string _smtpClientHost = string.Empty; + protected int _smtpClientPort; + protected string _popHost = string.Empty; + protected int _popPort; + private readonly ILogger _logger; + public AbstractMailWorker(ILogger logger) + { + _logger = logger; + } + public void MailConfig(MailConfigModel config) + { + _mailLogin = config.MailLogin; + _mailPassword = config.MailPassword; + _smtpClientHost = config.SmtpClientHost; + _smtpClientPort = config.SmtpClientPort; + _popHost = config.PopHost; + _popPort = config.PopPort; + _logger.LogDebug("Config: {login}, {password}, {clientHost}, {clientPort}, {popHost}, {popPort} ", _mailLogin, _mailPassword, _smtpClientHost, _smtpClientPort, _popHost, _popPort); + } + public async void MailSendAsync(MailSendInfoBindingModel info) + { + if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword)) + { + return; + } + if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0) + { + return; + } + if (string.IsNullOrEmpty(info.MailAddress) || string.IsNullOrEmpty(info.Subject) || (string.IsNullOrEmpty(info.Text) && info.Pdf == null)) + { + return; + } + _logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject); + await SendMailAsync(info); + } + protected abstract Task SendMailAsync(MailSendInfoBindingModel info); + } +} diff --git a/TravelAgency/TravelAgencyBusinessLogic/MailWorker/MailKitWorker.cs b/TravelAgency/TravelAgencyBusinessLogic/MailWorker/MailKitWorker.cs new file mode 100644 index 0000000..6127b4f --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/MailWorker/MailKitWorker.cs @@ -0,0 +1,47 @@ +using TravelAgencyContracts.BindingModels; +using TravelAgencyContracts.BusinessLogicsContracts; +using MailKit.Net.Pop3; +using MailKit.Security; +using Microsoft.Extensions.Logging; +using System.Net.Mail; +using System.Text; +using System.Net; + +namespace TravelAgencyBusinessLogic.MailWorker +{ + public class MailKitWorker : AbstractMailWorker + { + public MailKitWorker(ILogger logger) : base(logger) { } + protected override async Task SendMailAsync(MailSendInfoBindingModel info) + { + using var objMailMessage = new MailMessage(); + using var objSmtpClient = new SmtpClient(_smtpClientHost, _smtpClientPort); + try + { + objMailMessage.From = new MailAddress(_mailLogin); + objMailMessage.To.Add(new MailAddress(info.MailAddress)); + objMailMessage.Subject = info.Subject; + objMailMessage.SubjectEncoding = Encoding.UTF8; + objMailMessage.BodyEncoding = Encoding.UTF8; + if (info.Text != null) + { + objMailMessage.Body = info.Text; + } + if (info.Pdf != null) + { + var attachment = new Attachment (new MemoryStream(info.Pdf), info.FileName); + objMailMessage.Attachments.Add (attachment); + } + objSmtpClient.UseDefaultCredentials = false; + objSmtpClient.EnableSsl = true; + objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; + objSmtpClient.Credentials = new NetworkCredential(_mailLogin, _mailPassword); + await Task.Run(() => objSmtpClient.Send(objMailMessage)); + } + catch (Exception ex) + { + throw; + } + } + } +} diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToExcel.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToExcel.cs new file mode 100644 index 0000000..b0c2d4b --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToExcel.cs @@ -0,0 +1,125 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; + +namespace TravelAgencyBusinessLogic.OfficePackage +{ + public abstract class AbstractSaveToExcel + { + /// + /// Создание отчета + /// + /// + public void CreateReport(ExcelInfo info) + { + CreateExcel(info); + + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "A", + RowIndex = 1, + Text = info.Title, + StyleInfo = ExcelStyleInfoType.Title + }); + + MergeCells(new ExcelMergeParameters + { + CellFromName = "A1", + CellToName = "C1" + }); + + uint rowIndex = 2; + foreach (var tp in info.TourPlaces) + { + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "A", + RowIndex = rowIndex, + Text = $"Тур: {tp.Tour.TourName}.", + StyleInfo = ExcelStyleInfoType.Text + }); + rowIndex++; + + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "B", + RowIndex = rowIndex, + Text = "Места для посещения:", + StyleInfo = ExcelStyleInfoType.Text + }); + + MergeCells(new ExcelMergeParameters + { + CellFromName = $"B{rowIndex}", + CellToName = $"C{rowIndex}" + }); + + rowIndex++; + + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "B", + RowIndex = rowIndex, + Text = "Название:", + StyleInfo = ExcelStyleInfoType.Text + }); + + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "C", + RowIndex = rowIndex, + Text = "Адрес:", + StyleInfo = ExcelStyleInfoType.Text + }); + + rowIndex++; + + foreach (var place in tp.Places) + { + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "B", + RowIndex = rowIndex, + Text = place.PlaceName, + StyleInfo = ExcelStyleInfoType.TextWithBorder + }); + + InsertCellInWorksheet(new ExcelCellParameters + { + ColumnName = "C", + RowIndex = rowIndex, + Text = place.PlaceAddress, + StyleInfo = ExcelStyleInfoType.TextWithBorder + }); + + 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); + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToPdf.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToPdf.cs new file mode 100644 index 0000000..7f7e454 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToPdf.cs @@ -0,0 +1,77 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; + +namespace TravelAgencyBusinessLogic.OfficePackage +{ + public abstract class AbstractSaveToPdf + { + public void CreateDoc(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 { "2cm", "3cm", "3cm", "4cm", "3cm", "3cm"}); + + CreateRow(new PdfRowParameters + { + Texts = new List { "Тур", "Стоимость тура", "Дата тура", "Экскурсионная группа", "Количество участников", "Гид" }, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + + foreach (var tour in info.Tours) + { + CreateRow(new PdfRowParameters + { + Texts = new List { tour.Tour.TourName, tour.Tour.Price.ToString(), tour.Tour.TourDate.ToShortDateString(), "", "", "" }, + Style = "Normal", + ParagraphAlignment = PdfParagraphAlignmentType.Left + }); + foreach(var excursionGroup in tour.ExcursionGroups) + { + CreateRow(new PdfRowParameters + { + Texts = new List { "", "", "", excursionGroup.ExcursionGroupName, excursionGroup.ParticipantsAmount.ToString(), excursionGroup.GuideFIO}, + 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); + } +} diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToWord.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToWord.cs new file mode 100644 index 0000000..3118de4 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/AbstractSaveToWord.cs @@ -0,0 +1,90 @@ +using DocumentFormat.OpenXml.Wordprocessing; +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; + +namespace TravelAgencyBusinessLogic.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 tourPlace in info.TourPlaces) + { + CreateParagraph(new WordParagraph + { + Texts = new List<(string, WordTextProperties)> + { + ($"Тур: {tourPlace.Tour.TourName}. ", new WordTextProperties { Bold = true, Size = "24" }) + }, + TextProperties = new WordTextProperties + { + Size = "24", + JustificationType = WordJustificationType.Both + } + }); + + CreateParagraph(new WordParagraph + { + Texts = new List<(string, WordTextProperties)> + { + ("Места для посещения:", new WordTextProperties { Bold = true, Size = "24" }) + }, + TextProperties = new WordTextProperties + { + Size = "24", + JustificationType = WordJustificationType.Both + } + }); + + foreach (var place in tourPlace.Places) + { + CreateParagraph(new WordParagraph + { + Texts = new List<(string, WordTextProperties)> + { + ($"{place.PlaceName} - {place.PlaceAddress}", new WordTextProperties { Bold = false, 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/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs new file mode 100644 index 0000000..6ed08a3 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/ExcelStyleInfoType.cs @@ -0,0 +1,11 @@ +namespace TravelAgencyBusinessLogic.OfficePackage.HelperEnums +{ + public enum ExcelStyleInfoType + { + Title, + + Text, + + TextWithBorder + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs new file mode 100644 index 0000000..f3dbc46 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs @@ -0,0 +1,11 @@ +namespace TravelAgencyBusinessLogic.OfficePackage.HelperEnums +{ + public enum PdfParagraphAlignmentType + { + Center, + + Left, + + Right + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/WordJustificationType.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/WordJustificationType.cs new file mode 100644 index 0000000..77e6865 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperEnums/WordJustificationType.cs @@ -0,0 +1,9 @@ +namespace TravelAgencyBusinessLogic.OfficePackage.HelperEnums +{ + public enum WordJustificationType + { + Center, + + Both + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelCellParameters.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelCellParameters.cs new file mode 100644 index 0000000..b06f57a --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelCellParameters.cs @@ -0,0 +1,17 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + 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; } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelInfo.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelInfo.cs new file mode 100644 index 0000000..efc4430 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelInfo.cs @@ -0,0 +1,13 @@ +using TravelAgencyContracts.ViewModels; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class ExcelInfo + { + public string FileName { get; set; } = string.Empty; + + public string Title { get; set; } = string.Empty; + + public List TourPlaces { get; set; } = new(); + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelMergeParameters.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelMergeParameters.cs new file mode 100644 index 0000000..b8baffa --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/ExcelMergeParameters.cs @@ -0,0 +1,11 @@ +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class ExcelMergeParameters + { + public string CellFromName { get; set; } = string.Empty; + + public string CellToName { get; set; } = string.Empty; + + public string Merge => $"{CellFromName}:{CellToName}"; + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfInfo.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfInfo.cs new file mode 100644 index 0000000..1edeeb5 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfInfo.cs @@ -0,0 +1,17 @@ +using TravelAgencyContracts.ViewModels; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class PdfInfo + { + public MemoryStream FileName { get; set; } = new(); + + public string Title { get; set; } = string.Empty; + + public DateTime DateFrom { get; set; } + + public DateTime DateTo { get; set; } + + public List Tours { get; set; } = new(); + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs new file mode 100644 index 0000000..c1df995 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs @@ -0,0 +1,13 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class PdfParagraph + { + public string Text { get; set; } = string.Empty; + + public string Style { get; set; } = string.Empty; + + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs new file mode 100644 index 0000000..cbcd687 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs @@ -0,0 +1,13 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class PdfRowParameters + { + public List Texts { get; set; } = new(); + + public string Style { get; set; } = string.Empty; + + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs new file mode 100644 index 0000000..8c04d59 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs @@ -0,0 +1,13 @@ +using TravelAgencyContracts.ViewModels; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class WordInfo + { + public string FileName { get; set; } = string.Empty; + + public string Title { get; set; } = string.Empty; + + public List TourPlaces { get; set; } = new(); + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs new file mode 100644 index 0000000..650b031 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs @@ -0,0 +1,9 @@ +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class WordParagraph + { + public List<(string, WordTextProperties)> Texts { get; set; } = new(); + + public WordTextProperties? TextProperties { get; set; } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordTextProperties.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordTextProperties.cs new file mode 100644 index 0000000..586f157 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/HelperModels/WordTextProperties.cs @@ -0,0 +1,13 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; + +namespace TravelAgencyBusinessLogic.OfficePackage.HelperModels +{ + public class WordTextProperties + { + public string Size { get; set; } = string.Empty; + + public bool Bold { get; set; } + + public WordJustificationType JustificationType { get; set; } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToExcel.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToExcel.cs new file mode 100644 index 0000000..a2f1012 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToExcel.cs @@ -0,0 +1,292 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Office2010.Excel; +using DocumentFormat.OpenXml.Office2013.Excel; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Spreadsheet; + +namespace TravelAgencyBusinessLogic.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.TextWithBorder => 1U, + ExcelStyleInfoType.Text => 0U, + _ => 0U, + }; + } + + protected override void CreateExcel(ExcelInfo info) + { + _spreadsheetDocument = SpreadsheetDocument.Create(info.FileName, SpreadsheetDocumentType.Workbook); + // Создаем книгу (в ней хранятся листы) + 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.Dispose(); + } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToPdf.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToPdf.cs new file mode 100644 index 0000000..fb218a2 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToPdf.cs @@ -0,0 +1,114 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; +using MigraDoc.DocumentObjectModel; +using MigraDoc.DocumentObjectModel.Tables; +using MigraDoc.Rendering; + +namespace TravelAgencyBusinessLogic.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.Right => 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) + { + var renderer = new PdfDocumentRenderer(true) + { + Document = _document + }; + renderer.RenderDocument(); + renderer.PdfDocument.Save(info.FileName); + } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToWord.cs b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToWord.cs new file mode 100644 index 0000000..fbb54f4 --- /dev/null +++ b/TravelAgency/TravelAgencyBusinessLogic/OfficePackage/Implements/SaveToWord.cs @@ -0,0 +1,135 @@ +using TravelAgencyBusinessLogic.OfficePackage.HelperEnums; +using TravelAgencyBusinessLogic.OfficePackage.HelperModels; +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; + +namespace TravelAgencyBusinessLogic.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) + { + _wordDocument = WordprocessingDocument.Create(info.FileName, WordprocessingDocumentType.Document); + 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.Dispose(); + } + } +} \ No newline at end of file diff --git a/TravelAgency/TravelAgencyBusinessLogic/TravelAgencyBusinessLogic.csproj b/TravelAgency/TravelAgencyBusinessLogic/TravelAgencyBusinessLogic.csproj index bc89be4..441b082 100644 --- a/TravelAgency/TravelAgencyBusinessLogic/TravelAgencyBusinessLogic.csproj +++ b/TravelAgency/TravelAgencyBusinessLogic/TravelAgencyBusinessLogic.csproj @@ -7,7 +7,10 @@ + + + diff --git a/TravelAgency/TravelAgencyContracts/BindingModels/ExcursionBindingModel.cs b/TravelAgency/TravelAgencyContracts/BindingModels/ExcursionBindingModel.cs index b727909..8442693 100644 --- a/TravelAgency/TravelAgencyContracts/BindingModels/ExcursionBindingModel.cs +++ b/TravelAgency/TravelAgencyContracts/BindingModels/ExcursionBindingModel.cs @@ -14,6 +14,8 @@ namespace TravelAgencyContracts.BindingModels public int UserId { get; set; } + public int PlaceId { get; set; } + public Dictionary ExcursionTours { get; set; } = new(); } } diff --git a/TravelAgency/TravelAgencyContracts/BindingModels/MailConfigBindingModel.cs b/TravelAgency/TravelAgencyContracts/BindingModels/MailConfigBindingModel.cs new file mode 100644 index 0000000..c5379e0 --- /dev/null +++ b/TravelAgency/TravelAgencyContracts/BindingModels/MailConfigBindingModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TravelAgencyContracts.BindingModels +{ + public class MailConfigModel + { + 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/TravelAgency/TravelAgencyContracts/BindingModels/MailSendInfoBindingModel.cs b/TravelAgency/TravelAgencyContracts/BindingModels/MailSendInfoBindingModel.cs new file mode 100644 index 0000000..22140d6 --- /dev/null +++ b/TravelAgency/TravelAgencyContracts/BindingModels/MailSendInfoBindingModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TravelAgencyContracts.BindingModels +{ + public class MailSendInfoBindingModel + { + public string MailAddress { get; set; } = string.Empty; + public string Subject { get; set; } = string.Empty; + public string Text { get; set; } = string.Empty; + public byte[] Pdf { get; set; } + public string FileName { get; set; } = string.Empty; + } +} diff --git a/TravelAgency/TravelAgencyContracts/BindingModels/PlaceBindingModel.cs b/TravelAgency/TravelAgencyContracts/BindingModels/PlaceBindingModel.cs index ddcd0a7..d7b8f37 100644 --- a/TravelAgency/TravelAgencyContracts/BindingModels/PlaceBindingModel.cs +++ b/TravelAgency/TravelAgencyContracts/BindingModels/PlaceBindingModel.cs @@ -9,7 +9,5 @@ namespace TravelAgencyContracts.BindingModels public string PlaceName { get; set; } = string.Empty; public string PlaceAddress { get; set; } = string.Empty; - - public int ExcursionId { get; set; } } } diff --git a/TravelAgency/TravelAgencyContracts/BindingModels/ReportBindingModel.cs b/TravelAgency/TravelAgencyContracts/BindingModels/ReportBindingModel.cs new file mode 100644 index 0000000..9fb526e --- /dev/null +++ b/TravelAgency/TravelAgencyContracts/BindingModels/ReportBindingModel.cs @@ -0,0 +1,15 @@ +namespace TravelAgencyContracts.BindingModels +{ + public class ReportBindingModel + { + public string FileName { get; set; } = string.Empty; + + public DateTime? DateFrom { get; set; } + + public DateTime? DateTo { get; set; } + + public int UserId { get; set; } + + public List? Tours = new(); + } +} diff --git a/TravelAgency/TravelAgencyContracts/BusinessLogicsContracts/IReportLogic.cs b/TravelAgency/TravelAgencyContracts/BusinessLogicsContracts/IReportLogic.cs new file mode 100644 index 0000000..120ddcf --- /dev/null +++ b/TravelAgency/TravelAgencyContracts/BusinessLogicsContracts/IReportLogic.cs @@ -0,0 +1,16 @@ +using TravelAgencyContracts.BindingModels; +using TravelAgencyContracts.ViewModels; + +namespace TravelAgencyContracts.BusinessLogicsContracts +{ + public interface IReportLogic + { + List GetTourPlaces(ReportBindingModel model); + + List GetTourPeriod(ReportBindingModel model); + + void SaveTourPlacesToWordFile(ReportBindingModel model); + + void SaveTourPlacesToExcelFile(ReportBindingModel model); + } +} diff --git a/TravelAgency/TravelAgencyContracts/SearchModels/ExcursionSearchModel.cs b/TravelAgency/TravelAgencyContracts/SearchModels/ExcursionSearchModel.cs index 6adf2e1..930aea1 100644 --- a/TravelAgency/TravelAgencyContracts/SearchModels/ExcursionSearchModel.cs +++ b/TravelAgency/TravelAgencyContracts/SearchModels/ExcursionSearchModel.cs @@ -7,5 +7,7 @@ public string? ExcursionName { get; set; } public int? UserId { get; set; } + + public int? PlaceId { get; set; } } } diff --git a/TravelAgency/TravelAgencyContracts/SearchModels/PlaceSearchModel.cs b/TravelAgency/TravelAgencyContracts/SearchModels/PlaceSearchModel.cs index 26edf74..fd440fe 100644 --- a/TravelAgency/TravelAgencyContracts/SearchModels/PlaceSearchModel.cs +++ b/TravelAgency/TravelAgencyContracts/SearchModels/PlaceSearchModel.cs @@ -7,7 +7,5 @@ public string? PlaceName { get; set; } public string? PlaceAddress { get; set; } - - public int? ExcursionId { get; set; } } } diff --git a/TravelAgency/TravelAgencyContracts/SearchModels/TourSearchModel.cs b/TravelAgency/TravelAgencyContracts/SearchModels/TourSearchModel.cs index 6e7b621..be27b86 100644 --- a/TravelAgency/TravelAgencyContracts/SearchModels/TourSearchModel.cs +++ b/TravelAgency/TravelAgencyContracts/SearchModels/TourSearchModel.cs @@ -7,5 +7,9 @@ public string? TourName { get; set; } public int? UserId { get; set; } + + public DateTime? DateFrom { get; set; } + + public DateTime? DateTo { get; set; } } } diff --git a/TravelAgency/TravelAgencyContracts/ViewModels/ExcursionViewModel.cs b/TravelAgency/TravelAgencyContracts/ViewModels/ExcursionViewModel.cs index e7015b8..a6fa975 100644 --- a/TravelAgency/TravelAgencyContracts/ViewModels/ExcursionViewModel.cs +++ b/TravelAgency/TravelAgencyContracts/ViewModels/ExcursionViewModel.cs @@ -18,6 +18,10 @@ namespace TravelAgencyContracts.ViewModels public int UserId { get; set; } + public int PlaceId { get; set; } + + public string? PlaceName { get; set; } = string.Empty; + public Dictionary ExcursionTours { get; set; } = new(); } } diff --git a/TravelAgency/TravelAgencyContracts/ViewModels/PlaceViewModel.cs b/TravelAgency/TravelAgencyContracts/ViewModels/PlaceViewModel.cs index 737b87e..59bbe24 100644 --- a/TravelAgency/TravelAgencyContracts/ViewModels/PlaceViewModel.cs +++ b/TravelAgency/TravelAgencyContracts/ViewModels/PlaceViewModel.cs @@ -12,7 +12,5 @@ namespace TravelAgencyContracts.ViewModels [DisplayName("Адрес места")] public string PlaceAddress { get; set; } = string.Empty; - - public int ExcursionId { get; set; } } } diff --git a/TravelAgency/TravelAgencyContracts/ViewModels/ReportPlaceTourViewModel.cs b/TravelAgency/TravelAgencyContracts/ViewModels/ReportPlaceTourViewModel.cs deleted file mode 100644 index d6a95e4..0000000 --- a/TravelAgency/TravelAgencyContracts/ViewModels/ReportPlaceTourViewModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace TravelAgencyContracts.ViewModels -{ - public class ReportPlaceTourViewModel - { - public string TourName { get; set; } = string.Empty; - public List Places { get; set; } = new(); - } -} diff --git a/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPeriodViewModel.cs b/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPeriodViewModel.cs index 6f1b085..d775826 100644 --- a/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPeriodViewModel.cs +++ b/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPeriodViewModel.cs @@ -2,8 +2,10 @@ { public class ReportTourPeriodViewModel { - public string TourName { get; set; } = string.Empty; - public List ExcursionGroups { get; set; } = new(); - public List Guides { get; set; } = new(); + public TourViewModel Tour { get; set; } = new(); + + public HashSet ExcursionGroups { get; set; } = new(); + + public HashSet Guides { get; set; } = new(); } } diff --git a/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPlaceViewModel.cs b/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPlaceViewModel.cs new file mode 100644 index 0000000..3b63080 --- /dev/null +++ b/TravelAgency/TravelAgencyContracts/ViewModels/ReportTourPlaceViewModel.cs @@ -0,0 +1,9 @@ +namespace TravelAgencyContracts.ViewModels +{ + public class ReportTourPlaceViewModel + { + public TourViewModel Tour { get; set; } = new(); + + public HashSet Places { get; set; } = new(); + } +} diff --git a/TravelAgency/TravelAgencyDataModels/Models/IExcursionModel.cs b/TravelAgency/TravelAgencyDataModels/Models/IExcursionModel.cs index aa71d5d..3725c0f 100644 --- a/TravelAgency/TravelAgencyDataModels/Models/IExcursionModel.cs +++ b/TravelAgency/TravelAgencyDataModels/Models/IExcursionModel.cs @@ -10,6 +10,8 @@ int UserId { get; } + int PlaceId { get; } + Dictionary ExcursionTours { get; } } } diff --git a/TravelAgency/TravelAgencyDataModels/Models/IPlaceModel.cs b/TravelAgency/TravelAgencyDataModels/Models/IPlaceModel.cs index 8aebeb0..2bf338d 100644 --- a/TravelAgency/TravelAgencyDataModels/Models/IPlaceModel.cs +++ b/TravelAgency/TravelAgencyDataModels/Models/IPlaceModel.cs @@ -5,7 +5,5 @@ string PlaceName { get; } string PlaceAddress { get; } - - int ExcursionId { get; } } } diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Implements/ExcursionStorage.cs b/TravelAgency/TravelAgencyDatabaseImplement/Implements/ExcursionStorage.cs index f8a8f0b..ec8a6b7 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Implements/ExcursionStorage.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Implements/ExcursionStorage.cs @@ -14,6 +14,7 @@ namespace TravelAgencyDatabaseImplement.Implements using var context = new TravelAgencyDatabase(); return context.Excursions .Include(x => x.User) + .Include(x => x.Place) .Include(x => x.Tours) .ThenInclude(x => x.Tour) .ToList() @@ -28,6 +29,7 @@ namespace TravelAgencyDatabaseImplement.Implements { return context.Excursions .Include(x => x.User) + .Include(x => x.Place) .Include(x => x.Tours) .ThenInclude(x => x.Tour) .Where(x => x.ExcursionName.Contains(model.ExcursionName)) @@ -39,6 +41,7 @@ namespace TravelAgencyDatabaseImplement.Implements { return context.Excursions .Include(x => x.User) + .Include(x => x.Place) .Include(x => x.Tours) .ThenInclude(x => x.Tour) .Where(x => x.UserId.Equals(model.UserId)) @@ -46,6 +49,18 @@ namespace TravelAgencyDatabaseImplement.Implements .Select(x => x.GetViewModel) .ToList(); } + if (model.PlaceId.HasValue) + { + return context.Excursions + .Include(x => x.User) + .Include(x => x.Place) + .Include(x => x.Tours) + .ThenInclude(x => x.Tour) + .Where(x => x.PlaceId.Equals(model.PlaceId)) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } return new(); } @@ -58,6 +73,7 @@ namespace TravelAgencyDatabaseImplement.Implements using var context = new TravelAgencyDatabase(); return context.Excursions .Include(x => x.User) + .Include(x => x.Place) .Include(x => x.Tours) .ThenInclude(x => x.Tour) .FirstOrDefault(x => (!string.IsNullOrEmpty(model.ExcursionName) && x.ExcursionName == model.ExcursionName) || diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Implements/PlaceStorage.cs b/TravelAgency/TravelAgencyDatabaseImplement/Implements/PlaceStorage.cs index b5d3d34..e3a10fc 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Implements/PlaceStorage.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Implements/PlaceStorage.cs @@ -13,7 +13,6 @@ namespace TravelAgencyDatabaseImplement.Implements { using var context = new TravelAgencyDatabase(); return context.Places - .Include(x => x.Excursion) .Select(x => x.GetViewModel) .ToList(); } @@ -24,19 +23,10 @@ namespace TravelAgencyDatabaseImplement.Implements if (!string.IsNullOrEmpty(model.PlaceName)) { return context.Places - .Include(x => x.Excursion) .Where(x => x.PlaceName.Contains(model.PlaceName)) .Select(x => x.GetViewModel) .ToList(); } - if (model.ExcursionId.HasValue) - { - return context.Places - .Include(x => x.Excursion) - .Where(x => x.ExcursionId.Equals(model.ExcursionId)) - .Select(x => x.GetViewModel) - .ToList(); - } return new(); } @@ -75,7 +65,6 @@ namespace TravelAgencyDatabaseImplement.Implements context.Places.Add(newPlace); context.SaveChanges(); return context.Places - .Include(x => x.Excursion) .FirstOrDefault(x => x.Id == newPlace.Id) ?.GetViewModel; } @@ -91,7 +80,6 @@ namespace TravelAgencyDatabaseImplement.Implements place.Update(model); context.SaveChanges(); return context.Places - .Include(x => x.Excursion) .FirstOrDefault(x => x.Id == model.Id) ?.GetViewModel; } @@ -103,7 +91,6 @@ namespace TravelAgencyDatabaseImplement.Implements if (element != null) { var deletedElement = context.Places - .Include(x => x.Excursion) .FirstOrDefault(x => x.Id == model.Id) ?.GetViewModel; context.Places.Remove(element); diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Implements/TourStorage.cs b/TravelAgency/TravelAgencyDatabaseImplement/Implements/TourStorage.cs index 7b9a99d..693d5ae 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Implements/TourStorage.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Implements/TourStorage.cs @@ -21,23 +21,24 @@ namespace TravelAgencyDatabaseImplement.Implements public List GetFilteredList(TourSearchModel model) { using var context = new TravelAgencyDatabase(); - if (!string.IsNullOrEmpty(model.TourName)) - { - return context.Tours - .Include(x => x.User) - .Where(x => x.TourName.Contains(model.TourName)) + var tours = context.Tours.Include(x => x.User) .Select(x => x.GetViewModel) .ToList(); + + if (!string.IsNullOrEmpty(model.TourName)) + { + tours = tours.Where(x => x.TourName.Contains(model.TourName)).ToList(); } if (model.UserId.HasValue) { - return context.Tours - .Include(x => x.User) - .Where(x => x.UserId.Equals(model.UserId)) - .Select(x => x.GetViewModel) - .ToList(); + tours = tours.Where(x => x.UserId.Equals(model.UserId)).ToList(); } - return new(); + + if (model.DateFrom.HasValue && model.DateTo.HasValue) + { + tours = tours.Where(x => x.TourDate >= model.DateFrom && x.TourDate <= model.DateTo).ToList(); + } + return tours ?? new(); } public TourViewModel? GetElement(TourSearchModel model) diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240429175309_InitialCreate.Designer.cs b/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240529001818_InitialCreate.Designer.cs similarity index 97% rename from TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240429175309_InitialCreate.Designer.cs rename to TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240529001818_InitialCreate.Designer.cs index 82568c4..843c0f7 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240429175309_InitialCreate.Designer.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240529001818_InitialCreate.Designer.cs @@ -12,7 +12,7 @@ using TravelAgencyDatabaseImplement; namespace TravelAgencyDatabaseImplement.Migrations { [DbContext(typeof(TravelAgencyDatabase))] - [Migration("20240429175309_InitialCreate")] + [Migration("20240529001818_InitialCreate")] partial class InitialCreate { /// @@ -41,6 +41,9 @@ namespace TravelAgencyDatabaseImplement.Migrations .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("PlaceId") + .HasColumnType("int"); + b.Property("Price") .HasColumnType("float"); @@ -49,6 +52,8 @@ namespace TravelAgencyDatabaseImplement.Migrations b.HasKey("Id"); + b.HasIndex("PlaceId"); + b.HasIndex("UserId"); b.ToTable("Excursions"); @@ -163,9 +168,6 @@ namespace TravelAgencyDatabaseImplement.Migrations SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - b.Property("ExcursionId") - .HasColumnType("int"); - b.Property("PlaceAddress") .IsRequired() .HasColumnType("nvarchar(max)"); @@ -176,8 +178,6 @@ namespace TravelAgencyDatabaseImplement.Migrations b.HasKey("Id"); - b.HasIndex("ExcursionId"); - b.ToTable("Places"); }); @@ -292,12 +292,20 @@ namespace TravelAgencyDatabaseImplement.Migrations modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Excursion", b => { + b.HasOne("TravelAgencyDatabaseImplement.Models.Place", "Place") + .WithMany("Excursions") + .HasForeignKey("PlaceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("TravelAgencyDatabaseImplement.Models.User", "User") .WithMany("Excursions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); + b.Navigation("Place"); + b.Navigation("User"); }); @@ -358,17 +366,6 @@ namespace TravelAgencyDatabaseImplement.Migrations b.Navigation("Tour"); }); - modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Place", b => - { - b.HasOne("TravelAgencyDatabaseImplement.Models.Excursion", "Excursion") - .WithMany("Places") - .HasForeignKey("ExcursionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Excursion"); - }); - modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Tour", b => { b.HasOne("TravelAgencyDatabaseImplement.Models.User", "User") @@ -412,8 +409,6 @@ namespace TravelAgencyDatabaseImplement.Migrations modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Excursion", b => { - b.Navigation("Places"); - b.Navigation("Tours"); }); @@ -431,6 +426,8 @@ namespace TravelAgencyDatabaseImplement.Migrations modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Place", b => { + b.Navigation("Excursions"); + b.Navigation("Trips"); }); diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240429175309_InitialCreate.cs b/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240529001818_InitialCreate.cs similarity index 97% rename from TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240429175309_InitialCreate.cs rename to TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240529001818_InitialCreate.cs index 762d552..28bd31f 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240429175309_InitialCreate.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Migrations/20240529001818_InitialCreate.cs @@ -26,6 +26,20 @@ namespace TravelAgencyDatabaseImplement.Migrations table.PrimaryKey("PK_Guides", x => x.Id); }); + migrationBuilder.CreateTable( + name: "Places", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + PlaceName = table.Column(type: "nvarchar(max)", nullable: false), + PlaceAddress = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Places", x => x.Id); + }); + migrationBuilder.CreateTable( name: "Users", columns: table => new @@ -100,11 +114,18 @@ namespace TravelAgencyDatabaseImplement.Migrations ExcursionName = table.Column(type: "nvarchar(max)", nullable: false), ExcursionDescription = table.Column(type: "nvarchar(max)", nullable: false), Price = table.Column(type: "float", nullable: false), - UserId = table.Column(type: "int", nullable: false) + UserId = table.Column(type: "int", nullable: false), + PlaceId = table.Column(type: "int", nullable: false) }, constraints: table => { table.PrimaryKey("PK_Excursions", x => x.Id); + table.ForeignKey( + name: "FK_Excursions_Places_PlaceId", + column: x => x.PlaceId, + principalTable: "Places", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_Excursions_Users_UserId", column: x => x.UserId, @@ -137,22 +158,27 @@ namespace TravelAgencyDatabaseImplement.Migrations }); migrationBuilder.CreateTable( - name: "Places", + name: "TripPlaces", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - PlaceName = table.Column(type: "nvarchar(max)", nullable: false), - PlaceAddress = table.Column(type: "nvarchar(max)", nullable: false), - ExcursionId = table.Column(type: "int", nullable: false) + TripId = table.Column(type: "int", nullable: false), + PlaceId = table.Column(type: "int", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_Places", x => x.Id); + table.PrimaryKey("PK_TripPlaces", x => x.Id); table.ForeignKey( - name: "FK_Places_Excursions_ExcursionId", - column: x => x.ExcursionId, - principalTable: "Excursions", + name: "FK_TripPlaces_Places_PlaceId", + column: x => x.PlaceId, + principalTable: "Places", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TripPlaces_Trips_TripId", + column: x => x.TripId, + principalTable: "Trips", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); @@ -209,32 +235,6 @@ namespace TravelAgencyDatabaseImplement.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "TripPlaces", - columns: table => new - { - Id = table.Column(type: "int", nullable: false) - .Annotation("SqlServer:Identity", "1, 1"), - TripId = table.Column(type: "int", nullable: false), - PlaceId = table.Column(type: "int", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_TripPlaces", x => x.Id); - table.ForeignKey( - name: "FK_TripPlaces_Places_PlaceId", - column: x => x.PlaceId, - principalTable: "Places", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_TripPlaces_Trips_TripId", - column: x => x.TripId, - principalTable: "Trips", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateIndex( name: "IX_ExcursionGroups_GuideId", table: "ExcursionGroups", @@ -255,6 +255,11 @@ namespace TravelAgencyDatabaseImplement.Migrations table: "ExcursionGroupTours", column: "TourId"); + migrationBuilder.CreateIndex( + name: "IX_Excursions_PlaceId", + table: "Excursions", + column: "PlaceId"); + migrationBuilder.CreateIndex( name: "IX_Excursions_UserId", table: "Excursions", @@ -270,11 +275,6 @@ namespace TravelAgencyDatabaseImplement.Migrations table: "ExcursionTours", column: "TourId"); - migrationBuilder.CreateIndex( - name: "IX_Places_ExcursionId", - table: "Places", - column: "ExcursionId"); - migrationBuilder.CreateIndex( name: "IX_Tours_UserId", table: "Tours", @@ -312,22 +312,22 @@ namespace TravelAgencyDatabaseImplement.Migrations name: "ExcursionGroups"); migrationBuilder.DropTable( - name: "Tours"); + name: "Excursions"); migrationBuilder.DropTable( - name: "Places"); + name: "Tours"); migrationBuilder.DropTable( name: "Trips"); migrationBuilder.DropTable( - name: "Excursions"); - - migrationBuilder.DropTable( - name: "Guides"); + name: "Places"); migrationBuilder.DropTable( name: "Users"); + + migrationBuilder.DropTable( + name: "Guides"); } } } diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Migrations/TravelAgencyDatabaseModelSnapshot.cs b/TravelAgency/TravelAgencyDatabaseImplement/Migrations/TravelAgencyDatabaseModelSnapshot.cs index 249d06e..a3ca8a7 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Migrations/TravelAgencyDatabaseModelSnapshot.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Migrations/TravelAgencyDatabaseModelSnapshot.cs @@ -38,6 +38,9 @@ namespace TravelAgencyDatabaseImplement.Migrations .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("PlaceId") + .HasColumnType("int"); + b.Property("Price") .HasColumnType("float"); @@ -46,6 +49,8 @@ namespace TravelAgencyDatabaseImplement.Migrations b.HasKey("Id"); + b.HasIndex("PlaceId"); + b.HasIndex("UserId"); b.ToTable("Excursions"); @@ -160,9 +165,6 @@ namespace TravelAgencyDatabaseImplement.Migrations SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - b.Property("ExcursionId") - .HasColumnType("int"); - b.Property("PlaceAddress") .IsRequired() .HasColumnType("nvarchar(max)"); @@ -173,8 +175,6 @@ namespace TravelAgencyDatabaseImplement.Migrations b.HasKey("Id"); - b.HasIndex("ExcursionId"); - b.ToTable("Places"); }); @@ -289,12 +289,20 @@ namespace TravelAgencyDatabaseImplement.Migrations modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Excursion", b => { + b.HasOne("TravelAgencyDatabaseImplement.Models.Place", "Place") + .WithMany("Excursions") + .HasForeignKey("PlaceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("TravelAgencyDatabaseImplement.Models.User", "User") .WithMany("Excursions") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); + b.Navigation("Place"); + b.Navigation("User"); }); @@ -355,17 +363,6 @@ namespace TravelAgencyDatabaseImplement.Migrations b.Navigation("Tour"); }); - modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Place", b => - { - b.HasOne("TravelAgencyDatabaseImplement.Models.Excursion", "Excursion") - .WithMany("Places") - .HasForeignKey("ExcursionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Excursion"); - }); - modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Tour", b => { b.HasOne("TravelAgencyDatabaseImplement.Models.User", "User") @@ -409,8 +406,6 @@ namespace TravelAgencyDatabaseImplement.Migrations modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Excursion", b => { - b.Navigation("Places"); - b.Navigation("Tours"); }); @@ -428,6 +423,8 @@ namespace TravelAgencyDatabaseImplement.Migrations modelBuilder.Entity("TravelAgencyDatabaseImplement.Models.Place", b => { + b.Navigation("Excursions"); + b.Navigation("Trips"); }); diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Models/Excursion.cs b/TravelAgency/TravelAgencyDatabaseImplement/Models/Excursion.cs index d91f974..9377b8e 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Models/Excursion.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Models/Excursion.cs @@ -25,6 +25,11 @@ namespace TravelAgencyDatabaseImplement.Models [DeleteBehavior(DeleteBehavior.Restrict)] public virtual User User { get; set; } + [Required] + public int PlaceId { get; set; } + + public virtual Place Place { get; set; } + private Dictionary? _excursionTours = null; [NotMapped] @@ -44,9 +49,6 @@ namespace TravelAgencyDatabaseImplement.Models [ForeignKey("ExcursionId")] public virtual List Tours { get; set; } = new(); - [ForeignKey("ExcursionId")] - public virtual List Places { get; set; } = new(); - public static Excursion? Create(TravelAgencyDatabase context, ExcursionBindingModel? model) { if (model == null) @@ -60,6 +62,9 @@ namespace TravelAgencyDatabaseImplement.Models ExcursionDescription = model.ExcursionDescription, Price = model.Price, UserId = model.UserId, + PlaceId = model.PlaceId, + Place = context.Places + .First(x => x.Id == model.PlaceId), Tours = model.ExcursionTours.Select(x => new ExcursionTour { Tour = context.Tours.First(y => y.Id == x.Key) @@ -72,9 +77,13 @@ namespace TravelAgencyDatabaseImplement.Models { return; } + using var context = new TravelAgencyDatabase(); ExcursionName = model.ExcursionName; ExcursionDescription = model.ExcursionDescription; Price = model.Price; + PlaceId = model.PlaceId; + Place = context.Places + .First(x => x.Id == model.PlaceId); } public ExcursionViewModel GetViewModel => new() @@ -84,6 +93,8 @@ namespace TravelAgencyDatabaseImplement.Models ExcursionDescription = ExcursionDescription, Price = Price, UserId = UserId, + PlaceId = PlaceId, + PlaceName = Place?.PlaceName, ExcursionTours = ExcursionTours }; diff --git a/TravelAgency/TravelAgencyDatabaseImplement/Models/Place.cs b/TravelAgency/TravelAgencyDatabaseImplement/Models/Place.cs index 85ccf0e..a581980 100644 --- a/TravelAgency/TravelAgencyDatabaseImplement/Models/Place.cs +++ b/TravelAgency/TravelAgencyDatabaseImplement/Models/Place.cs @@ -21,14 +21,13 @@ namespace TravelAgencyDatabaseImplement.Models [Required] public string PlaceAddress { get; set; } = string.Empty; - [Required] - public int ExcursionId { get; set; } - - public virtual Excursion Excursion { get; set; } [ForeignKey("PlaceId")] public virtual List Trips { get; set; } = new(); + [ForeignKey("PlaceId")] + public virtual List Excursions { get; set; } = new(); + public static Place? Create(PlaceBindingModel? model) { if (model == null) @@ -39,8 +38,7 @@ namespace TravelAgencyDatabaseImplement.Models { Id = model.Id, PlaceName = model.PlaceName, - PlaceAddress = model.PlaceAddress, - ExcursionId = model.ExcursionId + PlaceAddress = model.PlaceAddress }; } public void Update(PlaceBindingModel? model) @@ -51,15 +49,13 @@ namespace TravelAgencyDatabaseImplement.Models } PlaceName = model.PlaceName; PlaceAddress = model.PlaceAddress; - ExcursionId = model.ExcursionId; } public PlaceViewModel GetViewModel => new() { Id = Id, PlaceName = PlaceName, - PlaceAddress = PlaceAddress, - ExcursionId = ExcursionId + PlaceAddress = PlaceAddress }; } } diff --git a/TravelAgency/TravelAgencyWebApp/Controllers/ExcursionController.cs b/TravelAgency/TravelAgencyWebApp/Controllers/ExcursionController.cs index c1181de..5577fe5 100644 --- a/TravelAgency/TravelAgencyWebApp/Controllers/ExcursionController.cs +++ b/TravelAgency/TravelAgencyWebApp/Controllers/ExcursionController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using DocumentFormat.OpenXml.Presentation; +using Microsoft.AspNetCore.Mvc; using TravelAgencyContracts.BindingModels; using TravelAgencyContracts.BusinessLogicsContracts; using TravelAgencyContracts.SearchModels; @@ -15,11 +16,14 @@ namespace TravelAgencyWebApp.Controllers private readonly ITourLogic _tourLogic; - public ExcursionController(ILogger logger, IExcursionLogic excursionLogic, ITourLogic tourLogic) + private readonly IPlaceLogic _placeLogic; + + public ExcursionController(ILogger logger, IExcursionLogic excursionLogic, ITourLogic tourLogic, IPlaceLogic placeLogic) { _logger = logger; _excursionLogic = excursionLogic; _tourLogic = tourLogic; + _placeLogic = placeLogic; } [HttpGet] @@ -49,18 +53,20 @@ namespace TravelAgencyWebApp.Controllers UserId = LoggedinUser.User.Id, }); + ViewBag.Places = _placeLogic.ReadList(null); + return View(); } [HttpPost] - public void CreateExcursion(string excursionName, string excursionDescription, double price, List tours) + public void CreateExcursion(string excursionName, string excursionDescription, int place, double price, List tours) { if (LoggedinUser.User == null) { throw new Exception("Необходимо авторизоваться!"); } - if (string.IsNullOrEmpty(excursionName) || string.IsNullOrEmpty(excursionDescription) || price <= 0 || tours == null) + if (string.IsNullOrEmpty(excursionName) || string.IsNullOrEmpty(excursionDescription) || price <= 0 || place <= 0 || tours == null) { throw new Exception("Введены не все данные!"); } @@ -77,6 +83,7 @@ namespace TravelAgencyWebApp.Controllers ExcursionDescription = excursionDescription, Price = price, UserId = LoggedinUser.User.Id, + PlaceId = place, ExcursionTours = excursionTours }); @@ -96,6 +103,8 @@ namespace TravelAgencyWebApp.Controllers UserId = LoggedinUser.User.Id, }); + ViewBag.Places = _placeLogic.ReadList(null); + return View(_excursionLogic.ReadElement(new ExcursionSearchModel { Id = id @@ -103,14 +112,14 @@ namespace TravelAgencyWebApp.Controllers } [HttpPost] - public void UpdateExcursion(int id, string excursionName, string excursionDescription, double price, List tours) + public void UpdateExcursion(int id, string excursionName, string excursionDescription, int place, double price, List tours) { if (LoggedinUser.User == null) { throw new Exception("Необходимо авторизоваться!"); } - if (string.IsNullOrEmpty(excursionName) || string.IsNullOrEmpty(excursionDescription) || price <= 0 || tours == null) + if (string.IsNullOrEmpty(excursionName) || string.IsNullOrEmpty(excursionDescription) || price <= 0 || place <= 0 || tours == null) { throw new Exception("Введены не все данные!"); } @@ -128,6 +137,7 @@ namespace TravelAgencyWebApp.Controllers ExcursionDescription = excursionDescription, Price = price, UserId = LoggedinUser.User.Id, + PlaceId = place, ExcursionTours = excursionTours }); diff --git a/TravelAgency/TravelAgencyWebApp/Controllers/HomeController.cs b/TravelAgency/TravelAgencyWebApp/Controllers/HomeController.cs index 8cb9ea6..89cc598 100644 --- a/TravelAgency/TravelAgencyWebApp/Controllers/HomeController.cs +++ b/TravelAgency/TravelAgencyWebApp/Controllers/HomeController.cs @@ -5,6 +5,12 @@ using Microsoft.AspNetCore.Mvc; using System.Diagnostics; using TravelAgencyContracts.BusinessLogicsContracts; using TravelAgencyContracts.SearchModels; +using TravelAgencyBusinessLogic.BusinessLogics; +using DocumentFormat.OpenXml.Spreadsheet; +using TravelAgencyBusinessLogic.OfficePackage; +using TravelAgencyBusinessLogic.MailWorker; +using DocumentFormat.OpenXml.Wordprocessing; +using TravelAgencyDatabaseImplement.Models; namespace TravelAgencyWebApp.Controllers { @@ -14,11 +20,26 @@ namespace TravelAgencyWebApp.Controllers private readonly IUserLogic _userLogic; - public HomeController(ILogger logger, IUserLogic userLogic) + private readonly IReportLogic _reportLogic; + + private readonly ITourLogic _tourLogic; + + private readonly IGuideLogic _guideLogic; + + private readonly AbstractSaveToPdf _pdfLogic; + + private readonly AbstractMailWorker _mailLogic; + + public HomeController(ILogger logger, IUserLogic userLogic, IReportLogic reportLogic, ITourLogic tourLogic, IGuideLogic guideLogic, AbstractSaveToPdf pdfLogic, AbstractMailWorker mailLogic) { _logger = logger; _userLogic = userLogic; - } + _reportLogic = reportLogic; + _tourLogic = tourLogic; + _guideLogic = guideLogic; + _pdfLogic = pdfLogic; + _mailLogic = mailLogic; + } public IActionResult Index() { @@ -41,21 +62,6 @@ namespace TravelAgencyWebApp.Controllers { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } - [HttpGet] - public IActionResult ReportMenu() - { - return View(); - } - [HttpGet] - public IActionResult ReportPlaceTour() - { - return View(new List()); - } - [HttpGet] - public IActionResult ReportTourPeriod() - { - return View(new List()); - } [HttpGet] public IActionResult Enter() @@ -130,5 +136,143 @@ namespace TravelAgencyWebApp.Controllers Response.Redirect("Enter"); } + [HttpGet] + public IActionResult ReportMenu() + { + return View(); + } + [HttpGet] + public IActionResult ReportTourPlace() + { + if (LoggedinUser.User == null) + { + return Redirect("~/Home/Enter"); + } + + ViewBag.Tours = _tourLogic.ReadList(new TourSearchModel + { + UserId = LoggedinUser.User.Id, + }); + + return View(); + } + + [HttpGet] + public IActionResult ReportTourPeriod() + { + if (LoggedinUser.User == null) + { + return Redirect("~/Home/Enter"); + } + + return View(); + } + + [HttpPost] + public IActionResult ReportTourPeriod(DateTime dateFrom, DateTime dateTo) + { + if (LoggedinUser.User == null) + { + return Redirect("~/Home/Enter"); + } + + if (dateFrom == DateTime.MinValue || dateTo == DateTime.MinValue) + { + throw new Exception("Введены не все данные!"); + } + + ViewBag.DateFrom = dateFrom; + ViewBag.DateTo = dateTo; + + return View(_reportLogic.GetTourPeriod(new ReportBindingModel + { + DateFrom = dateFrom, + DateTo = dateTo, + UserId = LoggedinUser.User.Id + })); + } + + [HttpPost] + public IActionResult CreateReport(List tours, string type) + { + if (LoggedinUser.User == null) + { + throw new Exception("Необходимо авторизоваться!"); + } + + if (tours == null) + { + throw new Exception("Выберите туры!"); + } + + if (type.Equals("docx")) + { + _reportLogic.SaveTourPlacesToWordFile(new ReportBindingModel + { + FileName = $@"C:\Users\User\Downloads\Список мест по турам{DateTime.Now.ToString("dd-MM-yyyy HH-mm-ss")}.docx", + UserId = LoggedinUser.User.Id, + Tours = tours + }); + } else if (type.Equals("xlsx")) + { + _reportLogic.SaveTourPlacesToExcelFile(new ReportBindingModel + { + FileName = $@"C:\Users\User\Downloads\Список мест по турам{DateTime.Now.ToString("dd-MM-yyyy HH-mm-ss")}.xlsx", + UserId = LoggedinUser.User.Id, + Tours = tours + }); + } + + ViewBag.Tours = _tourLogic.ReadList(new TourSearchModel + { + UserId = LoggedinUser.User.Id, + }); + + return View("ReportTourPlace", tours); + } + + [HttpPost] + public void SentPdfToMail(DateTime dateFrom, DateTime dateTo) + { + if (LoggedinUser.User == null) + { + throw new Exception("Необходимо авторизоваться!"); + } + + if (dateFrom == DateTime.MinValue || dateTo == DateTime.MinValue) + { + throw new Exception("Введены не все данные!"); + } + + using (MemoryStream memoryStream = new MemoryStream()) + { + SendMailReport(dateFrom, dateTo, memoryStream); + } + + Response.Redirect("/Home/ReportTourPeriod"); + } + + + public void SendMailReport(DateTime? dateFrom, DateTime? dateTo, MemoryStream stream) + { + var tours = _reportLogic.GetTourPeriod(new ReportBindingModel + { + DateFrom = dateFrom, + DateTo = dateTo, + UserId = LoggedinUser.User.Id, + }); + if (tours == null) + return; + _pdfLogic.CreateDoc(new() + { + DateFrom = dateFrom!.Value, + DateTo = dateTo!.Value, + FileName = stream, + Tours = tours, + Title = "Отчет" + }); + byte[] report = stream.GetBuffer(); + _mailLogic.MailSendAsync(new() { MailAddress = LoggedinUser.User.Email, Subject = "Отчет", FileName = "PdfReport.pdf", Pdf = report }); + } } } diff --git a/TravelAgency/TravelAgencyWebApp/Program.cs b/TravelAgency/TravelAgencyWebApp/Program.cs index 5b194d9..591c328 100644 --- a/TravelAgency/TravelAgencyWebApp/Program.cs +++ b/TravelAgency/TravelAgencyWebApp/Program.cs @@ -1,7 +1,11 @@ using TravelAgencyBusinessLogic.BusinessLogics; +using TravelAgencyBusinessLogic.OfficePackage.Implements; +using TravelAgencyBusinessLogic.OfficePackage; using TravelAgencyContracts.BusinessLogicsContracts; using TravelAgencyContracts.StoragesContracts; using TravelAgencyDatabaseImplement.Implements; +using TravelAgencyWebApp; +using TravelAgencyBusinessLogic.MailWorker; var builder = WebApplication.CreateBuilder(args); // Add services to the container. @@ -23,8 +27,33 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddSingleton(); + var app = builder.Build(); +var mailSender = app.Services.GetService(); +mailSender?.MailConfig(new() +{ + MailLogin = builder.Configuration?.GetSection("MailLogin")?.Value?.ToString() ?? string.Empty, + MailPassword = builder.Configuration?.GetSection("MailPassword")?.Value?.ToString() ?? string.Empty, + SmtpClientHost = builder.Configuration?.GetSection("SmtpClientHost")?.Value?.ToString() ?? string.Empty, + SmtpClientPort = Convert.ToInt32(builder.Configuration?.GetSection("SmtpClientPort")?.Value?.ToString()), + PopHost = builder.Configuration?.GetSection("PopHost")?.Value?.ToString() ?? string.Empty, + PopPort = Convert.ToInt32(builder.Configuration?.GetSection("PopPort")?.Value?.ToString()) + +}); + +var guideLogic = app.Services.GetService(); +var tripLogic = app.Services.GetService(); +var placeLogic = app.Services.GetService(); + +var seeder = new SeedingService(guideLogic, tripLogic, placeLogic); +seeder.SeedGuarantor(); + // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { diff --git a/TravelAgency/TravelAgencyWebApp/SeedingService.cs b/TravelAgency/TravelAgencyWebApp/SeedingService.cs new file mode 100644 index 0000000..41edad1 --- /dev/null +++ b/TravelAgency/TravelAgencyWebApp/SeedingService.cs @@ -0,0 +1,109 @@ +using DocumentFormat.OpenXml.Bibliography; +using System.Drawing; +using TravelAgencyBusinessLogic.BusinessLogics; +using TravelAgencyContracts.BindingModels; +using TravelAgencyContracts.BusinessLogicsContracts; +using TravelAgencyContracts.SearchModels; +using TravelAgencyContracts.ViewModels; +using TravelAgencyDatabaseImplement.Models; +using TravelAgencyDataModels.Models; + +namespace TravelAgencyWebApp +{ + public class SeedingService + { + private readonly IGuideLogic _guideLogic; + private readonly ITripLogic _tripLogic; + private readonly IPlaceLogic _placeLogic; + + public SeedingService(IGuideLogic guideLogic, ITripLogic tripLogic, IPlaceLogic placeLogic) + { + _guideLogic = guideLogic; + _tripLogic = tripLogic; + _placeLogic = placeLogic; + } + + public void SeedGuarantor() + { + if (_guideLogic.ReadList(null) == null || _guideLogic.ReadList(null)?.ToList().Count < 1) + { + string[] domains = { "gmail.com", "yahoo.com", "hotmail.com", "outlook.com" }; + string[] prefixes = { "ivan", "pavel", "", "anna", "sergei", "vasili" }; + + string[] firstNames = { "Иван", "Петр", "Алексей" }; + string[] lastNames = { "Иванов", "Петров", "Сидоров" }; + string[] middleNames = { "Иванович", "Петрович", "Алексеевич" }; + Random random = new Random(); + for (int i = 0; i < 10; i++) + { + string areaCode = random.Next(100, 1000).ToString(); + string firstPart = random.Next(100, 1000).ToString(); + string secondPart = random.Next(1000, 10000).ToString(); + string randomPrefix = prefixes[random.Next(prefixes.Length)]; + string randomDomain = domains[random.Next(domains.Length)]; + + string firstName = firstNames[random.Next(firstNames.Length)]; + string lastName = lastNames[random.Next(lastNames.Length)]; + string middleName = middleNames[random.Next(middleNames.Length)]; + + + _guideLogic.Create(new GuideBindingModel + { + GuideFIO = $"{lastName} {firstName} {middleName}", + Email = $"{randomPrefix}{i}@{randomDomain}", + PhoneNumber = $"+7 ({areaCode}) {firstPart}-{secondPart}" + }); + } + } + + if (_placeLogic.ReadList(null) == null || _placeLogic.ReadList(null)?.ToList().Count < 1) + { + string[] streets = { "Цветной бульвар", "Ленинградский проспект", "Тверская улица", "Пресненская набережная", "Садовая улица" }; + string[] cities = { "Москва", "Санкт-Петербург", "Новосибирск", "Екатеринбург" }; + Random random = new Random(); + for (int i = 0; i < 10; i++) + { + string street = streets[random.Next(streets.Length)]; + string city = cities[random.Next(cities.Length)]; + int houseNumber = random.Next(1, 100); + _placeLogic.Create(new PlaceBindingModel + { + PlaceName = $"Место {i}", + PlaceAddress = $"{city}, {street}, {houseNumber}" + }); + } + } + + if (_tripLogic.ReadList(null) == null || _tripLogic.ReadList(null)?.ToList().Count < 1) + { + var guides = _guideLogic.ReadList(null); + var places = _placeLogic.ReadList(null); + Random random = new Random(); + for (int i = 0; i < 10; i++) + { + int year = random.Next(2024, 2026); + int month = random.Next(1, 13); + int day = random.Next(1, 29); + int guideId = guides[random.Next(0, guides.Count)].Id; + + Dictionary tripPlaces = new Dictionary(); + foreach(var place in places) + { + if (random.Next(0, 2) == 1) + { + tripPlaces.Add(place.Id, place); + } + } + + _tripLogic.Create(new TripBindingModel + { + TripName = $"Поездка {i}", + TripDate = new DateTime(year, month, day), + GuideId = guideId, + TripPlaces = tripPlaces + }); + } + } + } + } +} diff --git a/TravelAgency/TravelAgencyWebApp/Views/Excursion/CreateExcursion.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Excursion/CreateExcursion.cshtml index 2372092..8a18b0e 100644 --- a/TravelAgency/TravelAgencyWebApp/Views/Excursion/CreateExcursion.cshtml +++ b/TravelAgency/TravelAgencyWebApp/Views/Excursion/CreateExcursion.cshtml @@ -17,6 +17,12 @@
Цена:
+
+
Место для посещения:
+
+ +
+
Туры
diff --git a/TravelAgency/TravelAgencyWebApp/Views/Excursion/Excursions.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Excursion/Excursions.cshtml index 30c0bf5..cf9d59b 100644 --- a/TravelAgency/TravelAgencyWebApp/Views/Excursion/Excursions.cshtml +++ b/TravelAgency/TravelAgencyWebApp/Views/Excursion/Excursions.cshtml @@ -34,6 +34,9 @@ Описание + + Место для посещения + Цена @@ -54,6 +57,9 @@ @Html.DisplayFor(modelItem => excursion.ExcursionDescription) + + @Html.DisplayFor(modelItem => excursion.PlaceName) + @Html.DisplayFor(modelItem => excursion.Price) diff --git a/TravelAgency/TravelAgencyWebApp/Views/Excursion/UpdateExcursion.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Excursion/UpdateExcursion.cshtml index 8d39013..df2a252 100644 --- a/TravelAgency/TravelAgencyWebApp/Views/Excursion/UpdateExcursion.cshtml +++ b/TravelAgency/TravelAgencyWebApp/Views/Excursion/UpdateExcursion.cshtml @@ -20,6 +20,18 @@
Цена:
+
+
Место для посещения:
+
+ +
+
Туры
diff --git a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportMenu.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportMenu.cshtml index 9ebe9b6..2439af2 100644 --- a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportMenu.cshtml +++ b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportMenu.cshtml @@ -5,7 +5,7 @@

Меню создания отчетов

- + Отчет мест для посещения по выбранным турам diff --git a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportPlaceTour.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportPlaceTour.cshtml deleted file mode 100644 index e87ab36..0000000 --- a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportPlaceTour.cshtml +++ /dev/null @@ -1,48 +0,0 @@ -@using TravelAgencyContracts.ViewModels - -@model List -@{ - ViewData["Title"] = "Places per tour report"; -} -
-

Список мест для посещения по выбранным турам

-
- -
- -
-
- -
- -
-
Выберите тур:
-
- -
-
- - - - - - - - - - @foreach (var tour in Model) - { - - - - - } - -
ТурМесто
@tour.TourName -
    - @foreach (var place in tour.Places) - { -
  • @place
  • - } -
-
\ No newline at end of file diff --git a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPeriod.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPeriod.cshtml index 78d4ca6..6ced129 100644 --- a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPeriod.cshtml +++ b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPeriod.cshtml @@ -13,53 +13,64 @@
-
- -
+
-
-
Начальная дата:
-
- +
+
Начальная дата:
+
+ +
-
-
-
Конечная дата:
-
- +
+
Конечная дата:
+
+ +
-
+ + + + + + - @foreach (var tour in Model) + @if (Model == null || Model.Count <= 0) { - - - - - + + } + else + { + foreach (var record in Model) + { + + + + + + + var excursionGroups = new List(record.ExcursionGroups); + var guides = new List(record.Guides); + for (int i = 0; i < excursionGroups.Count; i++) + { + + + + + + + + + } + } }
ТурСтоимость тураДата тура Экскурсионная группаКоличество участников Гид
@tour.TourName -
    - @foreach (var excursionGroup in tour.ExcursionGroups) - { -
  • @excursionGroup
  • - } -
-
-
    - @foreach (var guide in tour.Guides) - { -
  • @guide
  • - } -
-
Нет доступных данных@record.Tour.TourName@record.Tour.Price@record.Tour.TourDate
@excursionGroups[i].ExcursionGroupName@excursionGroups[i].ParticipantsAmount@guides[i].GuideFIO
diff --git a/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPlace.cshtml b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPlace.cshtml new file mode 100644 index 0000000..fde3716 --- /dev/null +++ b/TravelAgency/TravelAgencyWebApp/Views/Home/ReportTourPlace.cshtml @@ -0,0 +1,51 @@ +@using TravelAgencyContracts.ViewModels + +@model List +@{ + ViewData["Title"] = "Places per tour report"; +} +
+

Список мест для посещения по выбранным турам

+
+ +
+
Выберите тур:
+
+ + + + + + + + + @foreach (var tour in ViewBag.Tours) + { + var isChecked = false; + if (Model != null && Model.Count > 0) { + isChecked = Model.Any(x => x.Equals(tour.Id)); + } + + + + + } + +
НазваниеВыбор
@tour.TourName + +
+
+ +
+ +
+ + +
+
+ + +
+
+ +
\ No newline at end of file diff --git a/TravelAgency/TravelAgencyWebApp/appsettings.json b/TravelAgency/TravelAgencyWebApp/appsettings.json index 10f68b8..cac8568 100644 --- a/TravelAgency/TravelAgencyWebApp/appsettings.json +++ b/TravelAgency/TravelAgencyWebApp/appsettings.json @@ -5,5 +5,12 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + + "SmtpClientHost": "smtp.gmail.com", + "SmtpClientPort": "587", + "PopHost": "pop.gmail.com", + "PopPort": "995", + "MailLogin": "carrepairshoplab7@gmail.com", + "MailPassword": "mmxi snox imiz ugqq" }