From 93e0fe9524cd79b20099b21ba33f001b11d451ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=A4=D0=B5=D0=B4=D0=BE=D1=82?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 23 Jul 2024 20:29:10 +0400 Subject: [PATCH] Pdf Report Client --- .../BusinessLogic/ReportClientLogic.cs | 53 +++++- .../ElectronicsShopBusinessLogic.csproj | 1 + .../MailWorker/MailKitWorker.cs | 10 +- .../OfficePackage/AbstractSaveToPdfClient.cs | 65 +++++++ .../HelperEnums/PdfParagraphAlignmentType.cs | 13 ++ .../HelperModels/ExcelInfoClient.cs | 1 - .../HelperModels/PdfInfoClient.cs | 16 ++ .../HelperModels/PdfParagraph.cs | 14 ++ .../HelperModels/PdfRowParameters.cs | 14 ++ .../HelperModels/WordInfoClient.cs | 3 - .../Implements/SaveToExcelClient.cs | 2 +- .../Implements/SaveToPdfClient.cs | 98 +++++++++++ .../BindingModels/MailSendInfoBindingModel.cs | 4 +- .../BindingModels/ReportBindingModel.cs | 6 +- .../IReportClientLogic.cs | 20 ++- .../ElectronicsShopContracts.csproj | 1 + .../ViewModels/ReportProductsViewModel.cs | 4 +- .../Controllers/ClientController.cs | 41 ++++- .../ElectronicsShopRestAPI/Program.cs | 1 + ElectronicsShop/ElectronicsShopRestAPI/Report | Bin 0 -> 37522 bytes .../ElectronicsShopRestAPI/report.xlsx | Bin 2869 -> 0 bytes .../Controllers/HomeController.cs | 159 +++++++++--------- .../Views/Home/ReportSearch.cshtml | 3 +- 23 files changed, 425 insertions(+), 104 deletions(-) create mode 100644 ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/AbstractSaveToPdfClient.cs create mode 100644 ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs create mode 100644 ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfInfoClient.cs create mode 100644 ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs create mode 100644 ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs create mode 100644 ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToPdfClient.cs create mode 100644 ElectronicsShop/ElectronicsShopRestAPI/Report delete mode 100644 ElectronicsShop/ElectronicsShopRestAPI/report.xlsx diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/BusinessLogic/ReportClientLogic.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/BusinessLogic/ReportClientLogic.cs index fb5f831..655e733 100644 --- a/ElectronicsShop/ElectronicsShopBusinessLogic/BusinessLogic/ReportClientLogic.cs +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/BusinessLogic/ReportClientLogic.cs @@ -6,6 +6,9 @@ using ElectronicsShopContracts.BusinessLogicContracts; using ElectronicsShopContracts.SearchModels; using ElectronicsShopContracts.StorageContracts; using ElectronicsShopContracts.ViewModels; +using MigraDoc.DocumentObjectModel; +using PdfSharp.Pdf; +using System.Collections.Generic; namespace ElectronicsShopBusinessLogic.BusinessLogic { @@ -14,20 +17,49 @@ namespace ElectronicsShopBusinessLogic.BusinessLogic private readonly IPaymeantStorage _paymeantstorage; private readonly IProductStorage _productstorage; private readonly IOrderStorage _orderStorage; + private readonly ICostItemStorage _costItemStorage; private readonly AbstractSaveToExcelClient _saveToExcel; private readonly AbstractSaveToWordClient _saveToWord; + private readonly AbstractSaveToPdfClient _saveToPdf; public ReportClientLogic(AbstractSaveToExcelClient abstractSaveToExcelClient, AbstractSaveToWordClient abstractSaveToWordClient, - IPaymeantStorage paymeantStorage, IProductStorage productStorage, IOrderStorage orderStorage) { + IPaymeantStorage paymeantStorage, IProductStorage productStorage, IOrderStorage orderStorage, + AbstractSaveToPdfClient abstractSaveToPdfClient, ICostItemStorage costItemStorage) { _saveToExcel = abstractSaveToExcelClient; _saveToWord= abstractSaveToWordClient; _paymeantstorage = paymeantStorage; _productstorage = productStorage; _orderStorage = orderStorage; + _costItemStorage = costItemStorage; + _saveToPdf = abstractSaveToPdfClient; + } + + // Получение списка оплаченных товаров за период + public List? GetProducts (ReportBindingModel model) { + var paymeants = _paymeantstorage.GetFillteredList(new PaymeantSearchModel { + DateFrom = model.DateFrom, + DateTo = model.DateTo, + }); + + List? products = new(); + + foreach (var paymeant in paymeants) { + var order = _orderStorage.GetElement(new OrderSearchModel { ID = paymeant.OrderID }); + foreach (var product in order.ProductList) { + products.Add(new ReportProductsViewModel { + ID = product.Value.Item1.ID, + ProductName = product.Value.Item1.ProductName, + Price = product.Value.Item1.Price, + CostItemName = _costItemStorage.GetElement(new CostItemSearchModel { ID = product.Value.Item1.CostItemID }).Name + }); + } + } + + return products; } // получение списка оплат за период - public List GetPaymeants(ReportBindingModel model) + public List? GetPaymeants(ReportBindingModel model) { return _paymeantstorage.GetFillteredList(new PaymeantSearchModel { DateFrom = model.DateFrom, @@ -73,7 +105,7 @@ namespace ElectronicsShopBusinessLogic.BusinessLogic return list; } - public byte[] SavePaymeantToExcelFile(int _clientID) + public byte[]? SavePaymeantToExcelFile(int _clientID) { var document = _saveToExcel.CreateReport(new ExcelInfoClient { @@ -83,13 +115,24 @@ namespace ElectronicsShopBusinessLogic.BusinessLogic return document; } - public byte[] SavePaymeantToWordFile(int _clientID) + public byte[]? SavePaymeantToWordFile(int _clientID) { var document = _saveToWord.CreateDoc(new WordInfoClient { - Title = "Список оплат", + Title = "Список оплат и товаров", ListPaymeant = _paymeantstorage.GetFillteredList(new PaymeantSearchModel { ClientID = _clientID }), }); return document; } + + public PdfDocument SaveProductToPdfFile(ReportBindingModel model) { + var document = _saveToPdf.CreteDoc(new PdfInfoClient { + Title = "Список оплаченных товаров", + FileName = "Report", + DateFrom = model.DateFrom, + DateTo = model.DateTo, + Products = GetProducts(model) + }); + return document; + } } } \ No newline at end of file diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/ElectronicsShopBusinessLogic.csproj b/ElectronicsShop/ElectronicsShopBusinessLogic/ElectronicsShopBusinessLogic.csproj index c5144c7..338f66b 100644 --- a/ElectronicsShop/ElectronicsShopBusinessLogic/ElectronicsShopBusinessLogic.csproj +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/ElectronicsShopBusinessLogic.csproj @@ -12,6 +12,7 @@ + diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/MailWorker/MailKitWorker.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/MailWorker/MailKitWorker.cs index 47760c5..9df1536 100644 --- a/ElectronicsShop/ElectronicsShopBusinessLogic/MailWorker/MailKitWorker.cs +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/MailWorker/MailKitWorker.cs @@ -10,12 +10,14 @@ using System.Threading.Tasks; using ElectronicsShopContracts.BindingModels; using MailKit.Net.Pop3; using MailKit.Security; +using MigraDoc.DocumentObjectModel; namespace ElectronicsShopBusinessLogic.MailWorker { public class MailKitWorker : AbstractMailWorker { - public MailKitWorker(ILogger logger, IMessageInfoLogic messageInfoLogic, IClientLogic clientLogic) : base(logger, messageInfoLogic, clientLogic) { } + public MailKitWorker(ILogger logger, IMessageInfoLogic messageInfoLogic, + IClientLogic clientLogic) : base(logger, messageInfoLogic, clientLogic) { } protected override async Task SendMailAsync(MailSendInfoBindingModel info) { @@ -27,6 +29,12 @@ namespace ElectronicsShopBusinessLogic.MailWorker objMailMessage.To.Add(new MailAddress(info.MailAddress)); objMailMessage.Subject = info.Subject; objMailMessage.Body = info.Text; + + Attachment attachment = new Attachment(new MemoryStream(info.document), name: "Report.pdf"); + if (attachment != null) { + objMailMessage.Attachments.Add(attachment); + } + objMailMessage.SubjectEncoding = Encoding.UTF8; objMailMessage.BodyEncoding = Encoding.UTF8; diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/AbstractSaveToPdfClient.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/AbstractSaveToPdfClient.cs new file mode 100644 index 0000000..4c141e6 --- /dev/null +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/AbstractSaveToPdfClient.cs @@ -0,0 +1,65 @@ +using ElectronicsShopBusinessLogic.OfficePackage.HelperEnums; +using ElectronicsShopBusinessLogic.OfficePackage.HelperModels; +using MigraDoc.DocumentObjectModel; +using PdfSharp.Pdf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ElectronicsShopBusinessLogic.OfficePackage +{ + public abstract class AbstractSaveToPdfClient { + public PdfDocument CreteDoc (PdfInfoClient info) { + CretePdf(info); + + CreateParagraph(new PdfParagraph { + Text = info.Title, + Style = "NormalTitle", + alignmentType = PdfParagraphAlignmentType.Center, + }); + CreateParagraph(new PdfParagraph { + Text = $"c {info.DateFrom.ToShortDateString()} по {info.DateTo.ToShortDateString()}", + Style = "Normal", + alignmentType = PdfParagraphAlignmentType.Right + }); + + CreateTable(new List { "2cm", "6cm", "4cm", "6cm"}); + + CreateRow(new PdfRowParameters { + Text = new List { "Номер", "Товар", "Цена", "Статья затрат" }, + Style = "NormalTittle", + alignmentType = PdfParagraphAlignmentType.Center, + }); + + foreach (var products in info.Products) { + CreateRow(new PdfRowParameters { + Text = new List { products.ID.ToString(), products.ProductName.ToString(), products.Price.ToString(), + products.CostItemName.ToString()}, + Style = "Normal", + alignmentType = PdfParagraphAlignmentType.Left, + }); + } + CreateParagraph(new PdfParagraph { + Text = $"Итого: {info.Products.Sum(x => x.Price)}\t", + Style = "Normal", + alignmentType = PdfParagraphAlignmentType.Right + }); + + var document = SavePdf(info); + return document; + } + + // Создание doc-файла + protected abstract void CretePdf (PdfInfoClient info); + // Создание параграфа с текстом + protected abstract void CreateParagraph(PdfParagraph paragraph); + // Создание таблицы + protected abstract void CreateTable(List columns); + // Создание и заполнение строки + protected abstract void CreateRow(PdfRowParameters rowParameters); + // Сохранение файла + protected abstract PdfDocument SavePdf(PdfInfoClient info); + } +} diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs new file mode 100644 index 0000000..3d9afd4 --- /dev/null +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperEnums/PdfParagraphAlignmentType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ElectronicsShopBusinessLogic.OfficePackage.HelperEnums { + public enum PdfParagraphAlignmentType { + Center, + Left, + Right, + } +} diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/ExcelInfoClient.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/ExcelInfoClient.cs index 43dc843..2eeec49 100644 --- a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/ExcelInfoClient.cs +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/ExcelInfoClient.cs @@ -4,7 +4,6 @@ namespace ElectronicsShopBusinessLogic.OfficePackage.HelperModels { public class ExcelInfoClient { - public string FileName { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public List PaymeantProducts { get; set; } = new(); } diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfInfoClient.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfInfoClient.cs new file mode 100644 index 0000000..93f4dbe --- /dev/null +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfInfoClient.cs @@ -0,0 +1,16 @@ +using ElectronicsShopContracts.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ElectronicsShopBusinessLogic.OfficePackage.HelperModels { + public class PdfInfoClient { + public string FileName { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public DateTime DateFrom { get; set; } + public DateTime DateTo { get; set; } + public List? Products { get; set; } = new(); + } +} diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs new file mode 100644 index 0000000..4276c90 --- /dev/null +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfParagraph.cs @@ -0,0 +1,14 @@ +using ElectronicsShopBusinessLogic.OfficePackage.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ElectronicsShopBusinessLogic.OfficePackage.HelperModels { + public class PdfParagraph { + public string Text { get; set; } = string.Empty; + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType alignmentType { get; set; } + } +} diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs new file mode 100644 index 0000000..59034cf --- /dev/null +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/PdfRowParameters.cs @@ -0,0 +1,14 @@ +using ElectronicsShopBusinessLogic.OfficePackage.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ElectronicsShopBusinessLogic.OfficePackage.HelperModels { + public class PdfRowParameters { + public List Text { get; set; } = new(); + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType alignmentType { get; set; } + } +} diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/WordInfoClient.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/WordInfoClient.cs index d1d2430..7900d66 100644 --- a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/WordInfoClient.cs +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/HelperModels/WordInfoClient.cs @@ -5,10 +5,7 @@ namespace ElectronicsShopBusinessLogic.OfficePackage.HelperModels { public class WordInfoClient { - public string FileName { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public List ListPaymeant { get; set; } = new(); } } diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToExcelClient.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToExcelClient.cs index d00382c..6fb5e1c 100644 --- a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToExcelClient.cs +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToExcelClient.cs @@ -286,4 +286,4 @@ namespace ElectronicsShopBusinessLogic.OfficePackage.Implements return _mem.ToArray(); } } -} +} \ No newline at end of file diff --git a/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToPdfClient.cs b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToPdfClient.cs new file mode 100644 index 0000000..e98c2e0 --- /dev/null +++ b/ElectronicsShop/ElectronicsShopBusinessLogic/OfficePackage/Implements/SaveToPdfClient.cs @@ -0,0 +1,98 @@ +using DocumentFormat.OpenXml.Bibliography; +using ElectronicsShopBusinessLogic.OfficePackage.HelperEnums; +using ElectronicsShopBusinessLogic.OfficePackage.HelperModels; +using MigraDoc.DocumentObjectModel; +using MigraDoc.DocumentObjectModel.Tables; +using MigraDoc.Rendering; +using PdfSharp.Pdf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ElectronicsShopBusinessLogic.OfficePackage.Implements { + public class SaveToPdfClient : AbstractSaveToPdfClient { + + 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 CreateParagraph(PdfParagraph pdfParagraph) { + if (_section == null) { + return; + } + var paragraph = _section.AddParagraph(pdfParagraph.Text); + paragraph.Format.SpaceAfter = "1cm"; + paragraph.Format.Alignment = GetParagraphAlignment(pdfParagraph.alignmentType); + paragraph.Style = pdfParagraph.Style; + } + + protected override void CreateRow(PdfRowParameters rowParameters) { + if (_table == null) { + return; + } + var row = _table.AddRow(); + for (int i = 0; i < rowParameters.Text.Count; ++i) { + // заполнение ячейки (добавление параграфа в ячейку) + row.Cells[i].AddParagraph(rowParameters.Text[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.alignmentType); + row.Cells[i].VerticalAlignment = VerticalAlignment.Center; + } + } + + 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 CretePdf(PdfInfoClient info) { + _document = new Document(); + DefineStyles(_document); + // Ссылка нп первую секцию + _section = _document.AddSection(); + } + + protected override PdfDocument SavePdf(PdfInfoClient info) { + var renderer = new PdfDocumentRenderer(true) { + Document = _document, + }; + renderer.RenderDocument(); + renderer.PdfDocument.Save(info.FileName); + return renderer.PdfDocument; + } + } +} diff --git a/ElectronicsShop/ElectronicsShopContracts/BindingModels/MailSendInfoBindingModel.cs b/ElectronicsShop/ElectronicsShopContracts/BindingModels/MailSendInfoBindingModel.cs index 16cc1da..049f94e 100644 --- a/ElectronicsShop/ElectronicsShopContracts/BindingModels/MailSendInfoBindingModel.cs +++ b/ElectronicsShop/ElectronicsShopContracts/BindingModels/MailSendInfoBindingModel.cs @@ -1,4 +1,5 @@ -using System; +using MigraDoc.DocumentObjectModel; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,5 +12,6 @@ namespace ElectronicsShopContracts.BindingModels public string MailAddress { get; set; } = string.Empty; public string Subject { get; set; } = string.Empty; public string Text { get; set; } = string.Empty; + public byte[]? document { get; set; } } } diff --git a/ElectronicsShop/ElectronicsShopContracts/BindingModels/ReportBindingModel.cs b/ElectronicsShop/ElectronicsShopContracts/BindingModels/ReportBindingModel.cs index 23d818d..e47daa5 100644 --- a/ElectronicsShop/ElectronicsShopContracts/BindingModels/ReportBindingModel.cs +++ b/ElectronicsShop/ElectronicsShopContracts/BindingModels/ReportBindingModel.cs @@ -10,8 +10,8 @@ namespace ElectronicsShopContracts.BindingModels { public class ReportBindingModel { - public string FileName { get; set; } = string.Empty; - public DateTime? DateFrom { get; set; } - public DateTime? DateTo { get; set; } + public string ClientEmail { get; set; } = string.Empty; + public DateTime DateFrom { get; set; } + public DateTime DateTo { get; set; } } } diff --git a/ElectronicsShop/ElectronicsShopContracts/BusinessLogicContracts/IReportClientLogic.cs b/ElectronicsShop/ElectronicsShopContracts/BusinessLogicContracts/IReportClientLogic.cs index b3b8662..f307e90 100644 --- a/ElectronicsShop/ElectronicsShopContracts/BusinessLogicContracts/IReportClientLogic.cs +++ b/ElectronicsShop/ElectronicsShopContracts/BusinessLogicContracts/IReportClientLogic.cs @@ -1,6 +1,7 @@ -using DocumentFormat.OpenXml.Packaging; -using ElectronicsShopContracts.BindingModels; +using ElectronicsShopContracts.BindingModels; using ElectronicsShopContracts.ViewModels; +using MigraDoc.DocumentObjectModel; +using PdfSharp.Pdf; using System; using System.Collections.Generic; using System.Linq; @@ -12,12 +13,17 @@ namespace ElectronicsShopContracts.BusinessLogicContracts public interface IReportClientLogic { // получение списка товаров с указанием, в какие оплаты товар входит - List GetPaymeantProducts(int _clientID); + List? GetPaymeantProducts(int _clientID); // получения списка оплат - List GetPaymeants(ReportBindingModel model); - byte[] SavePaymeantToWordFile(int _clientID); + List? GetPaymeants(ReportBindingModel model); - // Сохранение компонент с указанием отчета в .excel - byte[] SavePaymeantToExcelFile(int _clientID); + // Сохранение отчета оплат в .word + byte[]? SavePaymeantToWordFile(int _clientID); + + // Сохранение отчета оплат с товарами в .excel + byte[]? SavePaymeantToExcelFile(int _clientID); + + // Отчет оплаченных товаров в .pdf + PdfDocument SaveProductToPdfFile(ReportBindingModel model); } } diff --git a/ElectronicsShop/ElectronicsShopContracts/ElectronicsShopContracts.csproj b/ElectronicsShop/ElectronicsShopContracts/ElectronicsShopContracts.csproj index 40b8cdc..5c52396 100644 --- a/ElectronicsShop/ElectronicsShopContracts/ElectronicsShopContracts.csproj +++ b/ElectronicsShop/ElectronicsShopContracts/ElectronicsShopContracts.csproj @@ -8,6 +8,7 @@ + diff --git a/ElectronicsShop/ElectronicsShopContracts/ViewModels/ReportProductsViewModel.cs b/ElectronicsShop/ElectronicsShopContracts/ViewModels/ReportProductsViewModel.cs index ddb61c8..1d05b7b 100644 --- a/ElectronicsShop/ElectronicsShopContracts/ViewModels/ReportProductsViewModel.cs +++ b/ElectronicsShop/ElectronicsShopContracts/ViewModels/ReportProductsViewModel.cs @@ -9,7 +9,9 @@ namespace ElectronicsShopContracts.ViewModels { public class ReportProductsViewModel { + public int ID { get; set; } public string ProductName { get; set; } = string.Empty; - public List Products { get; set; } = new(); + public double Price { get; set; } + public string CostItemName { get; set; } = string.Empty; } } diff --git a/ElectronicsShop/ElectronicsShopRestAPI/Controllers/ClientController.cs b/ElectronicsShop/ElectronicsShopRestAPI/Controllers/ClientController.cs index 8bce23e..34349e0 100644 --- a/ElectronicsShop/ElectronicsShopRestAPI/Controllers/ClientController.cs +++ b/ElectronicsShop/ElectronicsShopRestAPI/Controllers/ClientController.cs @@ -1,10 +1,14 @@ using DocumentFormat.OpenXml.Drawing.Diagrams; using DocumentFormat.OpenXml.Packaging; +using ElectronicsShopBusinessLogic.BusinessLogic; +using ElectronicsShopBusinessLogic.MailWorker; using ElectronicsShopContracts.BindingModels; using ElectronicsShopContracts.BusinessLogicContracts; using ElectronicsShopContracts.SearchModels; using ElectronicsShopContracts.ViewModels; +using ElectronicsShopDataBaseImplement.Models; using Microsoft.AspNetCore.Mvc; +using MigraDoc.Rendering; namespace ElectronicsShopRestAPI.Controllers { @@ -17,12 +21,15 @@ namespace ElectronicsShopRestAPI.Controllers { private readonly IClientLogic _logic; private readonly IPaymeantLogic _payLogic; private readonly IReportClientLogic _reportLogic; + private readonly AbstractMailWorker _mailWorker; - public ClientController(ILogger logger, IClientLogic logic, IPaymeantLogic payLogic, IReportClientLogic reportlogic) { + public ClientController(ILogger logger, IClientLogic logic, IPaymeantLogic payLogic, IReportClientLogic reportlogic, + AbstractMailWorker mailWorker) { _logger = logger; _logic = logic; _payLogic = payLogic; _reportLogic = reportlogic; + _mailWorker = mailWorker; } [HttpGet] @@ -81,11 +88,11 @@ namespace ElectronicsShopRestAPI.Controllers { } } [HttpGet] - public List? GetReport(DateTime _start, DateTime _end) { + public List? GetReport(string _start,string _end) { try { var dataSource = _reportLogic.GetPaymeants(new ReportBindingModel { - DateFrom = _start, - DateTo = _end + DateFrom = DateTime.Parse(_start), + DateTo = DateTime.Parse(_end) }); return dataSource; } @@ -118,5 +125,31 @@ namespace ElectronicsShopRestAPI.Controllers { throw; } } + + [HttpPost] + public void SendReportMail (ReportBindingModel model) { + try { + + var doc = _reportLogic.SaveProductToPdfFile(model); + + MemoryStream stream = new MemoryStream(); + doc.Save(stream, true); + byte[] data = stream.ToArray(); + + + _mailWorker.MailSendAsync(new() { + MailAddress = model.ClientEmail, + Subject = "Отчет", + Text = $"Отчет оплаченных товаров с {model.DateFrom} по {model.DateTo}", + document = data + }); + + } + catch (Exception ex) { + _logger.LogError(ex, $"Ошибка создания файла"); + throw; + } + } + } } diff --git a/ElectronicsShop/ElectronicsShopRestAPI/Program.cs b/ElectronicsShop/ElectronicsShopRestAPI/Program.cs index 76cd9f5..f62b45e 100644 --- a/ElectronicsShop/ElectronicsShopRestAPI/Program.cs +++ b/ElectronicsShop/ElectronicsShopRestAPI/Program.cs @@ -29,6 +29,7 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/ElectronicsShop/ElectronicsShopRestAPI/Report b/ElectronicsShop/ElectronicsShopRestAPI/Report new file mode 100644 index 0000000000000000000000000000000000000000..358bb8b55ce340172f70ad792bb3dbd239ee33a7 GIT binary patch literal 37522 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 bQ#80-9CkHnP;-1h29?ReEnMj8?S}gk5QENF literal 0 HcmV?d00001 diff --git a/ElectronicsShop/ElectronicsShopRestAPI/report.xlsx b/ElectronicsShop/ElectronicsShopRestAPI/report.xlsx deleted file mode 100644 index a86d406031e7da665601d86b6141c5e9786b1b76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2869 zcma)82{@E%8y?9tjmW+)V=UR48OvD85HYr_C0k({Gbm=58G8*Sm6NgWsceme6j~6K zr4s72PMOFqN*sHH|5MjF4!{4p{%?P;?|bg|yYKgT?)SB~=G-a-0)ZePX4;4g@uA#k zE6`Hn0D*P__b`8CD4BBN7@2$m5f{@IbPHB$i+7ZWV2$Qxc^q&3)T+ z{~?KrR&+$NlzffD+iCLH?0hn;o8>QJR1*3}pI)_n*$!oBMxNCmx z^tK1iKMXDEt5HmCmfJP4pd7?^UP%$ClY<;|Gt6i=3kZUB3!*B)T_(M_n z&x72o#IJ)PwU>=CuUUp_r~kOqHbHFf{7`9fFx@PctMQ)o&qVH>F;&xzvpp(B$ZQKi z<|lWoF1KC@S{%P)uLv#Ks8 z2#oW_iBK~ZdlV)y%~l?`yB$mQWid5TLG<^8asxhE-F}OR6^p{Y~ zwSvDQ5tx~?iG7X}8LY{o0qucchV^t>5I@4ig*P7C78ANHuF<(HpAxO0rr+C`3Kf%{ zTIMWuI1bSSt5oKmIN=i2!@xnt^LNO)i9N6^Ue2a}c$4;1S;+%eyX=QJLqw|2C z$k(?b#&@bmw|0NeRSCy4crsHCo^Tc;>Blr{F!&N5wFk7Fs;LSkSSS*ONA1%Ws|FZV z;%-9@&2?wJt}nic%!CO2rQkO%aAuIsJOX|rrUFcvQ)@9{W-&@b-&RsORnIS7uS_9AWW^IUI=vhN&2Rw zWLw>f5G40F3Vjo1>S_i}VPrn{r*|CR6%-r&q|QpF>IgKjd^}!KwZ=Z`{xc?mwI$g! zcaQpes{~VOzR+EH7e@Bg$7ZZWFLa9pIF<_P>V@nJaV$14QY&SouBfG2ppC-%S@eG7 zL$l^5vh?qBj*8h?=TwqLW!H1K+`jPrCh+f~fPabo=CJBtR9^ytMg`~qH;vVzcCu^Z zjX~{LOjn(A=t0?BIHNQxFMReq);*2(Xt-hwCn35kmlH_cO_o4^wOdMI<`=sD%pvWlolW3ykh54(0W975v2evQ1WbmRfP z1dV&6Ce;V-u5|2+GScz|5v$knx`zfv06ka; zfkO2olQ3`%1PTr#knm)0Ub3^9^A;#z>(mOqXAz~efhUgh1EtRZl ztJ6ihG_YkW7~cZswz!nL`=U&Vv$9j^^P9C_luG%hdPjJ2=Gg3rNb!itGjbu_XnTz}L=-otEneUI34Pa(GPU)Fl%o;jwH1?8% zqOvO@emheYAzopHXhUN5u#-Estrv@t$IO8Onb!-5B?yS+zMo8@0VC(RI^fi!tHo8G zVq@F%%Ot`t9xGPoGqJ2y_UG7+@X}9xa${v6J8jxuT~EN-E2jV=R|G9lYr7IY9*JL^ zS}OFg>lTiD=8N}jwmMu8?RCtj=`O$g%wW08y_v6a93r12Zt-(E)EFC{^ypnN=^Ran@E>+2WH7%cdZyO3}l`z0+GopZlz zHh+;z1^?Nd^Qd;APh4}Fai|_BDU{-Ijiqy> zPaGR*Z_Tkq=$DypzPtkT``5N1pEm|?T&1i<&H|6CZvD@iWn<_@YhMff$+@}FZ$#K= ztZN95w*IqB{4bkbL)qNA)=-ML)*0Da;N~T|7B~a`)&2h{*o` _logger; - private Dictionary _productList; + private Dictionary _productList; public int Id; public HomeController(ILogger logger) { @@ -28,10 +29,10 @@ namespace ElectronicsShopUserApp.Controllers { [HttpGet] public IActionResult Index() { - if (APIClient.Client == null) { + if (APIClient.Client == null) { return Redirect("~/Home/Enter"); - } - return View(APIClient.GetRequset>($"api/client/getpaymeants?_clientid={APIClient.Client.ID}")); + } + return View(APIClient.GetRequset>($"api/client/getpaymeants?_clientid={APIClient.Client.ID}")); } [HttpGet] @@ -63,7 +64,7 @@ namespace ElectronicsShopUserApp.Controllers { Response.Redirect("Index"); } - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } @@ -73,7 +74,7 @@ namespace ElectronicsShopUserApp.Controllers { return View(); } - [HttpPost] + [HttpPost] public void Enter(string email, string password) { if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) { throw new Exception(" "); @@ -110,7 +111,7 @@ namespace ElectronicsShopUserApp.Controllers { var view = APIClient.GetRequset>($"api/main/getorders?_clientid={APIClient.Client.ID}"); - return View(view); + return View(view); } [HttpGet] @@ -123,45 +124,45 @@ namespace ElectronicsShopUserApp.Controllers { DateCreate = DateTime.Now, }); return RedirectToAction("OrderView"); - } + } [HttpGet] public IActionResult DeleteOrder(int id) { - APIClient.PostRequest($"api/main/deleteorders", new OrderBindingModel { ID = id }); + APIClient.PostRequest($"api/main/deleteorders", new OrderBindingModel { ID = id }); return RedirectToAction("Orders"); - } + } [HttpGet] public IActionResult EditOrder(int id) { - if (APIClient.Client == null) { - return Redirect("~/Home/Enter"); - } + if (APIClient.Client == null) { + return Redirect("~/Home/Enter"); + } if (id == 0) { return RedirectToAction("Orders"); } - var products = APIClient.GetRequset>>($"api/main/getorderproducts?_orderid={id}"); + var products = APIClient.GetRequset>>($"api/main/getorderproducts?_orderid={id}"); - foreach (var pr in products) { - var product = JsonConvert.DeserializeObject(pr[0]); - int count = JsonConvert.DeserializeObject(pr[1]); - _productList.Add(product.ID, (product, count)); - } + foreach (var pr in products) { + var product = JsonConvert.DeserializeObject(pr[0]); + int count = JsonConvert.DeserializeObject(pr[1]); + _productList.Add(product.ID, (product, count)); + } - (int, Dictionary) tuple = (id, _productList); - return View(tuple); - } + (int, Dictionary) tuple = (id, _productList); + return View(tuple); + } [HttpPost] - public void EditOrder(double sum, int id) { - if (sum <= 0) { - APIClient.PostRequest($"api/main/deleteorders", new OrderBindingModel { ID = id }); - } + public void EditOrder(double sum, int id) { + if (sum <= 0) { + APIClient.PostRequest($"api/main/deleteorders", new OrderBindingModel { ID = id }); + } - Response.Redirect("Orders"); - } + Response.Redirect("Orders"); + } - [HttpGet] + [HttpGet] public IActionResult OrderView() { if (APIClient.Client == null) { return Redirect("~/Home/Enter"); @@ -174,10 +175,10 @@ namespace ElectronicsShopUserApp.Controllers { var products = APIClient.GetRequset>>($"api/main/getorderproducts?_orderid={view?.ID}"); foreach (var pr in products) { - var product = JsonConvert.DeserializeObject(pr[0]); + var product = JsonConvert.DeserializeObject(pr[0]); int count = JsonConvert.DeserializeObject(pr[1]); _productList.Add(product.ID, (product, count)); - } + } (int, Dictionary) tuple = (Id, _productList); return View(tuple); @@ -186,71 +187,66 @@ namespace ElectronicsShopUserApp.Controllers { [HttpPost] public void OrderView(double sum, int id) { if (sum <= 0) { - APIClient.PostRequest($"api/main/deleteorders", new OrderBindingModel { ID = id}); + APIClient.PostRequest($"api/main/deleteorders", new OrderBindingModel { ID = id }); } Response.Redirect("Orders"); } [HttpGet] public IActionResult DeleteProductOrder(int id) { - var view = APIClient.GetRequset($"api/main/getorder?_clientid={APIClient.Client?.ID}"); - APIClient.PostRequestStr($"api/main/deleteproductorder", view.ID, id); + var view = APIClient.GetRequset($"api/main/getorder?_clientid={APIClient.Client?.ID}"); + APIClient.PostRequestStr($"api/main/deleteproductorder", view.ID, id); - return RedirectToAction("OrderView"); + return RedirectToAction("OrderView"); } - [HttpGet] + [HttpGet] public IActionResult AddProduct() { ViewBag.Products = APIClient.GetRequset>($"api/main/getproducts"); - return View(); + return View(); } - [HttpPost] + [HttpPost] public void AddProduct(int product, int count) { var _product = APIClient.GetRequset($"api/main/getproduct?_productid={product}"); var _order = APIClient.GetRequset($"api/main/getorder?_clientid={APIClient.Client?.ID}"); - APIClient.ListPostRequest($"api/main/addproduct", _product, count, _order.ID); - Response.Redirect("OrderView"); - } + APIClient.ListPostRequest($"api/main/addproduct", _product, count, _order.ID); + Response.Redirect("OrderView"); + } [HttpGet] - public IActionResult Message() - { + public IActionResult Message() { //ViewBag.Reports = APIClient.GetRequset>($"api/main/getproducts"); return View(); } [HttpGet] - public IActionResult Payment(int id) - { - if (APIClient.Client == null) - { - return Redirect("~/Home/Enter"); - } + public IActionResult Payment(int id) { + if (APIClient.Client == null) { + return Redirect("~/Home/Enter"); + } - if (id == 0) - { + if (id == 0) { return Redirect("~/Home/Index"); - } - var products = APIClient.GetRequset>>($"api/main/getorderproducts?_orderid={id}"); + } + var products = APIClient.GetRequset>>($"api/main/getorderproducts?_orderid={id}"); - foreach (var pr in products) - { - var product = JsonConvert.DeserializeObject(pr[0]); - int count = JsonConvert.DeserializeObject(pr[1]); - _productList.Add(product.ID, (product, count)); - } + foreach (var pr in products) { + var product = JsonConvert.DeserializeObject(pr[0]); + int count = JsonConvert.DeserializeObject(pr[1]); + _productList.Add(product.ID, (product, count)); + } - (int, Dictionary) tuple = (id, _productList); - return View(tuple); - } + (int, Dictionary) tuple = (id, _productList); + return View(tuple); + } [HttpPost] public void Payment(double sum, double paysum, int id) { - if (APIClient.Client == null) { - throw new Exception(" "); - } + if (APIClient.Client == null) { + throw new Exception(" "); + } if (paysum <= 0) { throw new Exception(" 0"); } @@ -265,7 +261,7 @@ namespace ElectronicsShopUserApp.Controllers { DatePaymeant = DateTime.Now, }); Response.Redirect("Index"); - } + } [HttpPost] public PaymeantOption PayOptionCalc(double sum, double paysum) { @@ -280,10 +276,10 @@ namespace ElectronicsShopUserApp.Controllers { } } [HttpPost] - public double Calc(int count, int product) { - var _product = APIClient.GetRequset($"api/main/getproduct?_productid={product}"); - return count * (_product?.Price ?? 1); - } + public double Calc(int count, int product) { + var _product = APIClient.GetRequset($"api/main/getproduct?_productid={product}"); + return count * (_product?.Price ?? 1); + } [HttpGet] public IActionResult Report() { @@ -295,31 +291,32 @@ namespace ElectronicsShopUserApp.Controllers { } [HttpPost] - public void Report(DateTime DateFrom, DateTime DateTo) { + public void Report(DateTime DateFrom, DateTime DateTo){ if (DateTo == DateTime.MinValue || DateFrom > DateTo) { throw new Exception(" "); } - Response.Redirect($"ReportSearch?_datefrom={DateFrom}&_dateTo={DateTo}"); + Response.Redirect($"ReportSearch?_datefrom={DateFrom}&_dateto={DateTo}"); } [HttpGet] - public IActionResult ReportSearch(DateTime _datefrom, DateTime _dateto) { + public IActionResult ReportSearch(string _datefrom, string _dateto) { + var reports = APIClient.GetRequset>($"api/client/getreport?_start={_datefrom}&_end={_dateto}"); - (DateTime, DateTime, List) tuple = (_datefrom, _dateto, reports); + (DateTime, DateTime, List?) tuple = (DateTime.Parse(_datefrom), DateTime.Parse(_dateto), reports); return View(tuple); } [HttpGet] public IActionResult CreateExcelReport() { - var fileMemStream = APIClient.GetRequset($"api/Client/CreateXlsxReport?_clientID={APIClient.Client.ID}"); + var fileMemStream = APIClient.GetRequset($"api/Client/CreateXlsxReport?_clientID={APIClient.Client.ID}"); if (fileMemStream == null) { throw new Exception(" "); } return File(fileMemStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Report.xlsx"); - } + } [HttpGet] public IActionResult CreateWordReport() { @@ -331,5 +328,15 @@ namespace ElectronicsShopUserApp.Controllers { return File(fileMemStream, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Report.docx"); } + + [HttpGet] + public IActionResult CreatePdfReport(string DateFrom, string DateTo) { + APIClient.PostRequest("api/client/SendReportMail", new ReportBindingModel { + ClientEmail = APIClient.Client.Email, + DateFrom = DateTime.Parse(DateFrom), + DateTo = DateTime.Parse(DateTo) + }); + return View("Report"); + } } } \ No newline at end of file diff --git a/ElectronicsShop/ElectronicsShopShopClientApp/Views/Home/ReportSearch.cshtml b/ElectronicsShop/ElectronicsShopShopClientApp/Views/Home/ReportSearch.cshtml index 2d5f000..b1d18d7 100644 --- a/ElectronicsShop/ElectronicsShopShopClientApp/Views/Home/ReportSearch.cshtml +++ b/ElectronicsShop/ElectronicsShopShopClientApp/Views/Home/ReportSearch.cshtml @@ -27,7 +27,8 @@