From 209c6bfa2916ac2dce0b07c173a2d7f84ac2b7cd Mon Sep 17 00:00:00 2001 From: LivelyPuer Date: Wed, 25 Dec 2024 15:44:54 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D0=B5=D1=86=20=D1=81=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D1=81=D1=82=D1=80=D0=B0.=20=D0=9F=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=8F=D1=82=D1=8C=20=D0=BD=D0=B5=20=D0=B1?= =?UTF-8?q?=D1=83=D0=B4=D0=B5=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectOpticsStore/Entities/Customer.cs | 6 +- .../ProjectOpticsStore/Entities/Order.cs | 35 ++++--- .../Entities/Order_Product.cs | 12 ++- .../ProjectOpticsStore/Entities/Product.cs | 14 +++ .../ProjectOpticsStore/Entities/Store.cs | 16 ++- .../ProjectOpticsStore/Entities/Supply.cs | 21 +++- .../Entities/TempOrderProduct.cs | 16 --- .../ProjectOpticsStore/Forms/FormCustomers.cs | 1 + .../Forms/FormDirectoryReport.Designer.cs | 2 +- .../ProjectOpticsStore/Forms/FormOrder.cs | 41 +++++--- .../ProjectOpticsStore/Forms/FormOrders.cs | 8 +- .../ProjectOpticsStore/Forms/FormProduct.cs | 2 +- .../ProjectOpticsStore/Forms/FormProducts.cs | 55 ++++++++++- .../Forms/FormStore.Designer.cs | 48 +++++++-- .../ProjectOpticsStore/Forms/FormStore.cs | 11 ++- .../ProjectOpticsStore/Forms/FormStores.cs | 2 + .../ProjectOpticsStore/Forms/FormSupplies.cs | 2 + .../ProjectOpticsStore/Forms/FormSupply.cs | 4 +- .../ProjectOpticsStore.csproj | 1 + .../ProjectOpticsStore/Reports/ChartReport.cs | 88 +++++++++++------ .../ProjectOpticsStore/Reports/DocReport.cs | 6 +- .../ProjectOpticsStore/Reports/TableReport.cs | 98 +++++++++++-------- .../Repositories/IOrderRepository.cs | 3 +- .../Implementations/OrderRepository.cs | 78 ++++++++++++--- .../Implementations/QueryBuilder.cs | 33 +++++++ .../Implementations/StoreRepository.cs | 7 +- .../Implementations/SupplyRepository.cs | 46 ++++++++- 27 files changed, 489 insertions(+), 167 deletions(-) delete mode 100644 ProjectOpticsStore/ProjectOpticsStore/Entities/TempOrderProduct.cs create mode 100644 ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/QueryBuilder.cs diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/Customer.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/Customer.cs index b82790a..f110ab6 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/Customer.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Entities/Customer.cs @@ -1,8 +1,12 @@ -namespace ProjectOpticsStore.Entities; +using System.ComponentModel; + +namespace ProjectOpticsStore.Entities; public class Customer { public int Id { get; private set; } + + [DisplayName("ФИО заказчика")] public string FullName { get; private set; } = string.Empty; public static Customer CreateEntity(int id, string fullName) diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/Order.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/Order.cs index fcdfc19..ed80be5 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/Order.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Entities/Order.cs @@ -1,15 +1,33 @@ using Newtonsoft.Json; using ProjectOpticsStore.Entities; using ProjectOpticsStore.Entities.Enums; +using System.ComponentModel; +using System.Linq; public class Order { public int Id { get; private set; } - public int CustomerId { get; private set; } - public DateTime DateCreated { get; private set; } + [Browsable(false)] + public int CustomerId { get; private set; } + + [DisplayName("Заказчик")] + public string CustomerName { get; private set; } = string.Empty; + + [DisplayName("Товары")] + + // Объединение строк + public string Product => OrderProducts != null ? + string.Join(", ", OrderProducts.Select(x => $"{x.Type} {x.Quantity}")) : + string.Empty; + + [DisplayName("Cтатус")] public OrderStatusEnum Status { get; private set; } = OrderStatusEnum.Pending; + [DisplayName("Дата заказа")] + public DateTime DateCreated { get; private set; } + + [Browsable(false)] // Коллекция, описывающая связь "Order_Product" [JsonIgnore] public IEnumerable OrderProducts { get; private set; } = new List(); @@ -24,16 +42,11 @@ public class Order OrderProducts = orderProducts }; } - - public static Order CreateOperation(TempOrderProduct tempOrderProduct, IEnumerable orderProducts) + public void SetOrderProducts(IEnumerable products) { - return new Order + if (products != null && products.Any()) { - Id = tempOrderProduct.Id, - CustomerId = tempOrderProduct.CustomerId, - DateCreated = tempOrderProduct.DateCreated, - Status = tempOrderProduct.Status, - OrderProducts = orderProducts - }; + OrderProducts = products; + } } } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/Order_Product.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/Order_Product.cs index 3569d33..68f8821 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/Order_Product.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Entities/Order_Product.cs @@ -1,18 +1,26 @@ -namespace ProjectOpticsStore.Entities; +using ProjectOpticsStore.Entities.Enums; +using System.ComponentModel; + +namespace ProjectOpticsStore.Entities; public class Order_Product { public int OrderId { get; private set; } + public int ProductId { get; private set; } + + public ProductTypeEnum Type { get; private set; } + public int Quantity { get; private set; } // Создание элемента связи - public static Order_Product CreateElement(int orderId, int productId, int quantity) + public static Order_Product CreateElement(int orderId, int productId, ProductTypeEnum type, int quantity) { return new Order_Product { OrderId = orderId, ProductId = productId, + Type = type, Quantity = quantity }; } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/Product.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/Product.cs index d80ea3b..1ae8826 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/Product.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Entities/Product.cs @@ -1,15 +1,29 @@ using ProjectOpticsStore.Entities.Enums; +using System.ComponentModel; public class Product { public int Id { get; private set; } + + [DisplayName("Тип Товара")] public ProductTypeEnum Type { get; private set; } + + [DisplayName("Мощность")] public double Power { get; private set; } + + [DisplayName("Цена")] public int Price { get; private set; } + + [DisplayName("Магазин")] public int Store { get; private set; } + + [DisplayName("Толщина (чево)")] public float Thickness { get; private set; } + + [DisplayName("Болезнь")] public string Disease { get; private set; } = string.Empty; + public static Product CreateEntity(int id, ProductTypeEnum type, double power, int price, int store, float thickness, string disease) { return new Product diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/Store.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/Store.cs index cb2ca36..6b68d5b 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/Store.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Entities/Store.cs @@ -1,16 +1,26 @@ -namespace ProjectOpticsStore.Entities; +using System.ComponentModel; + +namespace ProjectOpticsStore.Entities; public class Store { public int Id { get; private set; } + + [DisplayName("Адрес магазина")] public string Address { get; private set; } = string.Empty; - public static Store CreateEntity(int id, string address) + [DisplayName("Организация")] + public string Organisation { get; private set; } = string.Empty; //Добавил тут новое поле (зря) + + public string FullInformation => $"{Address} {Organisation}"; + + public static Store CreateEntity(int id, string address, string organisation) { return new Store { Id = id, - Address = address ?? string.Empty + Address = address ?? string.Empty, + Organisation = organisation ?? string.Empty }; } } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/Supply.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/Supply.cs index 4dfec73..e5a84f0 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/Supply.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Entities/Supply.cs @@ -1,13 +1,30 @@ -namespace ProjectOpticsStore.Entities; +using ProjectOpticsStore.Entities.Enums; +using System.ComponentModel; + +namespace ProjectOpticsStore.Entities; public class Supply { public int Id { get; private set; } + + [Browsable(false)] public int StoreId { get; private set; } - public DateTime OperationDate { get; private set; } + + [Browsable(false)] public int ProductId { get; private set; } // Связь многие-к-одному с товарами + + [DisplayName("Магазин")] + public string StoreName { get; private set; } = string.Empty; //Добавил имя магазина + + [DisplayName("Товар")] + public string ProductName { get; private set; } = string.Empty; + + [DisplayName("Количество")] public int Quantity { get; private set; } // Количество поставленного товара + [DisplayName("Дата спецоперации")] + public DateTime OperationDate { get; private set; } + public static Supply CreateOperation(int id, int storeId, int productId, int quantity) { return new Supply diff --git a/ProjectOpticsStore/ProjectOpticsStore/Entities/TempOrderProduct.cs b/ProjectOpticsStore/ProjectOpticsStore/Entities/TempOrderProduct.cs deleted file mode 100644 index e1fa218..0000000 --- a/ProjectOpticsStore/ProjectOpticsStore/Entities/TempOrderProduct.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ProjectOpticsStore.Entities.Enums; - -namespace ProjectOpticsStore.Entities; - -public class TempOrderProduct -{ - public int Id { get; private set; } - public int CustomerId { get; private set; } - public DateTime DateCreated { get; private set; } - - public OrderStatusEnum Status { get; private set; } - - public int OrderId { get; private set; } - public int ProductId { get; private set; } - public int Quantity { get; private set; } -} diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormCustomers.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormCustomers.cs index fb421c0..0c1b2ff 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormCustomers.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormCustomers.cs @@ -84,6 +84,7 @@ public partial class FormCustomers : Form private void LoadList() { dataGridViewData.DataSource = _customerRepository.ReadCustomers(); + dataGridViewData.Columns["Id"].Visible = false; } private bool TryGetIdentifierFromSelectedRow(out int id) diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormDirectoryReport.Designer.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormDirectoryReport.Designer.cs index 1c6e109..0f39ba8 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormDirectoryReport.Designer.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormDirectoryReport.Designer.cs @@ -85,7 +85,7 @@ Controls.Add(checkBoxCustomers); Name = "FormDirectoryReport"; StartPosition = FormStartPosition.CenterParent; - Text = "FormDirectoryReport"; + Text = "Отчет по т.н. справочникам"; ResumeLayout(false); PerformLayout(); } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrder.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrder.cs index 7dde527..4e4c96c 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrder.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrder.cs @@ -19,12 +19,10 @@ public partial class FormOrder : Form _customerRepository = customerRepository ?? throw new ArgumentNullException(nameof(customerRepository)); _productRepository = productRepository ?? throw new ArgumentNullException(nameof(productRepository)); - // Настройка ComboBox для выбора клиента - comboBoxCustomer.DataSource = _customerRepository.ReadCustomers() - .Select(c => new { c.Id }) - .ToList(); - comboBoxCustomer.DisplayMember = "Id"; - comboBoxCustomer.ValueMember = "Id"; + // Инициализация ComboBox для магазинов + comboBoxCustomer.DataSource = _customerRepository.ReadCustomers().ToList(); + comboBoxCustomer.DisplayMember = "FullName"; // Отображаем фио заказчиков + comboBoxCustomer.ValueMember = "Id"; // Значение это идентификатор заказчика comboBoxCustomer.DropDownStyle = ComboBoxStyle.DropDownList; // Настройка ComboBox для выбора статуса заказа @@ -54,9 +52,9 @@ public partial class FormOrder : Form var productColumn = new DataGridViewComboBoxColumn { Name = "ColumnProduct", - HeaderText = "Товар", + HeaderText = "Товары", DataSource = _productRepository.ReadProducts() - .Select(p => new { p.Id, p.Type }) // Пример данных: Id и Name + .Select(p => new { p.Id, p.Type }) // Пример данных: Id и Type .ToList(), DisplayMember = "Type", ValueMember = "Id", @@ -73,6 +71,15 @@ public partial class FormOrder : Form }; dataGridViewProducts.Columns.Add(quantityColumn); + // Столбец "Тип" + var typeColumn = new DataGridViewTextBoxColumn + { + Name = "ColumnType", + ValueType = typeof(int), + Visible = false // Скрываем столбец + }; + dataGridViewProducts.Columns.Add(typeColumn); + productColumn.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; quantityColumn.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; } @@ -117,11 +124,19 @@ public partial class FormOrder : Form if (row.Cells["ColumnProduct"].Value == null || row.Cells["ColumnQuantity"].Value == null) continue; - list.Add(Order_Product.CreateElement(0, Convert.ToInt32(row.Cells["ColumnProduct"].Value), - Convert.ToInt32(row.Cells["ColumnQuantity"].Value))); - } - return list.GroupBy(x => x.ProductId, x => x.Quantity, (id, quantity) => - Order_Product.CreateElement(0, id, quantity.Sum())).ToList(); + var productId = Convert.ToInt32(row.Cells["ColumnProduct"].Value); + var quantity = Convert.ToInt32(row.Cells["ColumnQuantity"].Value); + // Какой же говнокод + var typeValue = row.Cells["ColumnType"].Value?.ToString(); + ProductTypeEnum type = ProductTypeEnum.Glasses; + list.Add(Order_Product.CreateElement(0, productId, type, quantity)); + } + + return list.GroupBy( + x => new { x.ProductId, x.Type }, // Группируем по ProductId и Type + x => x.Quantity, + (key, quantity) => Order_Product.CreateElement(0, key.ProductId, key.Type, quantity.Sum()) + ).ToList(); } } \ No newline at end of file diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrders.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrders.cs index b994147..912656e 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrders.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormOrders.cs @@ -49,12 +49,10 @@ public partial class FormOrders : Form // Метод для загрузки списка заказов в DataGridView private void LoadList() { - dataGridViewOrders.DataSource = _orderRepository.ReadOrders(); - //if (dataGridViewOrders.Columns.Contains("OrderProducts")) - //{ - // dataGridViewOrders.Columns["OrderProducts"].Visible = false; - //} + dataGridViewOrders.DataSource = _orderRepository.ReadOrders(); + dataGridViewOrders.Columns["Id"].Visible = false; + dataGridViewOrders.Columns["DateCreated"].DefaultCellStyle.Format = "dd MMMM yyyy hh:mm"; } // Метод для получения идентификатора заказа из выбранной строки в DataGridView diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProduct.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProduct.cs index cc50fc2..d2f3cf8 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProduct.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProduct.cs @@ -63,7 +63,7 @@ public partial class FormProduct : Form // Инициализация ComboBox для магазинов comboBoxStore.DataSource = _storeRepository.ReadStores().ToList(); - comboBoxStore.DisplayMember = "Address"; // Отображаем адрес магазина + comboBoxStore.DisplayMember = "FullInformation"; // Отображаем полную информацию о магазине comboBoxStore.ValueMember = "Id"; // Значение это идентификатор магазина } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProducts.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProducts.cs index 24461b1..de3ea1a 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProducts.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormProducts.cs @@ -1,5 +1,6 @@ using ProjectOpticsStore.Entities; using ProjectOpticsStore.Repositories; +using System.ComponentModel; using Unity; namespace ProjectOpticsStore.Forms; @@ -88,10 +89,60 @@ public partial class FormProducts : Form private void LoadList() { - // Загрузка списка товаров в DataGridView - dataGridViewProducts.DataSource = _productRepository.ReadProducts().ToList(); + // Загружаем список товаров + var products = _productRepository.ReadProducts().ToList(); + + // Преобразуем данные с FullInformation магазинов + var productsWithStoreInfo = products.Select(product => + { + var store = _container.Resolve().ReadStoreById(product.Store); + return new + { + product.Id, + product.Type, + product.Power, + product.Price, + Store = store?.FullInformation, //деваться некуда, приходится передавать FullInformation + product.Thickness, + product.Disease + }; + }).ToList(); + + // Привязываем данные к DataGridView + dataGridViewProducts.DataSource = productsWithStoreInfo; + + // Настраиваем заголовки колонок на основе DisplayName + ApplyDisplayNames(); + + dataGridViewProducts.Columns["Id"].Visible = false; } + //После обновления метода LoadList у меня все русские заголовки с DisplayName перестали работать, поэтому + //мною было принято решение о создании нового метода, который может и костыльно, но это фиксит. Главное что оно работает + private void ApplyDisplayNames() + { + foreach (var column in dataGridViewProducts.Columns.Cast()) + { + // Получаем свойство, соответствующее колонке, из типа Product + var property = typeof(Product).GetProperty(column.DataPropertyName); + if (property == null) + { + continue; + } + + // Читаем атрибут DisplayName + var displayNameAttr = property.GetCustomAttributes(typeof(DisplayNameAttribute), false) + .FirstOrDefault() as DisplayNameAttribute; + + // Если атрибут найден, задаем его значение в качестве заголовка + if (displayNameAttr != null) + { + column.HeaderText = displayNameAttr.DisplayName; + } + } + } + + private bool TryGetIdentifierFromSelectedRow(out int id) { id = 0; diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.Designer.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.Designer.cs index 052a254..2fac3b3 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.Designer.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.Designer.cs @@ -32,30 +32,34 @@ labelFullName = new Label(); buttonSave = new Button(); buttonCancel = new Button(); + textBoxOrganisation = new TextBox(); + labelOrganisation = new Label(); SuspendLayout(); // // textBoxAddress // - textBoxAddress.Location = new Point(134, 69); + textBoxAddress.Location = new Point(133, 52); + textBoxAddress.Margin = new Padding(3, 2, 3, 2); textBoxAddress.Name = "textBoxAddress"; - textBoxAddress.Size = new Size(295, 27); + textBoxAddress.Size = new Size(243, 23); textBoxAddress.TabIndex = 1; // // labelFullName // labelFullName.AutoSize = true; labelFullName.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 204); - labelFullName.Location = new Point(22, 65); + labelFullName.Location = new Point(19, 49); labelFullName.Name = "labelFullName"; - labelFullName.Size = new Size(71, 28); + labelFullName.Size = new Size(56, 21); labelFullName.TabIndex = 4; labelFullName.Text = "Адрес:"; // // buttonSave // - buttonSave.Location = new Point(40, 278); + buttonSave.Location = new Point(35, 208); + buttonSave.Margin = new Padding(3, 2, 3, 2); buttonSave.Name = "buttonSave"; - buttonSave.Size = new Size(124, 40); + buttonSave.Size = new Size(108, 30); buttonSave.TabIndex = 5; buttonSave.Text = "Сохранить"; buttonSave.UseVisualStyleBackColor = true; @@ -63,23 +67,45 @@ // // buttonCancel // - buttonCancel.Location = new Point(206, 278); + buttonCancel.Location = new Point(180, 208); + buttonCancel.Margin = new Padding(3, 2, 3, 2); buttonCancel.Name = "buttonCancel"; - buttonCancel.Size = new Size(124, 40); + buttonCancel.Size = new Size(108, 30); buttonCancel.TabIndex = 6; buttonCancel.Text = "Отмена"; buttonCancel.UseVisualStyleBackColor = true; buttonCancel.Click += ButtonCancel_Click; // + // textBoxOrganisation + // + textBoxOrganisation.Location = new Point(133, 127); + textBoxOrganisation.Margin = new Padding(3, 2, 3, 2); + textBoxOrganisation.Name = "textBoxOrganisation"; + textBoxOrganisation.Size = new Size(243, 23); + textBoxOrganisation.TabIndex = 7; + // + // labelOrganisation + // + labelOrganisation.AutoSize = true; + labelOrganisation.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 204); + labelOrganisation.Location = new Point(19, 127); + labelOrganisation.Name = "labelOrganisation"; + labelOrganisation.Size = new Size(108, 21); + labelOrganisation.TabIndex = 8; + labelOrganisation.Text = "Организация:"; + // // FormStore // - AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(469, 341); + ClientSize = new Size(410, 256); + Controls.Add(labelOrganisation); + Controls.Add(textBoxOrganisation); Controls.Add(buttonCancel); Controls.Add(buttonSave); Controls.Add(labelFullName); Controls.Add(textBoxAddress); + Margin = new Padding(3, 2, 3, 2); Name = "FormStore"; Text = "Магазины"; ResumeLayout(false); @@ -92,5 +118,7 @@ private Label labelFullName; private Button buttonSave; private Button buttonCancel; + private TextBox textBoxOrganisation; + private Label labelOrganisation; } } \ No newline at end of file diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.cs index fad22a5..cef4028 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStore.cs @@ -1,4 +1,5 @@ -using ProjectOpticsStore.Entities; +using DocumentFormat.OpenXml.Office2010.PowerPoint; +using ProjectOpticsStore.Entities; using ProjectOpticsStore.Repositories; namespace ProjectOpticsStore.Forms; @@ -22,6 +23,7 @@ public partial class FormStore : Form } textBoxAddress.Text = store.Address; + textBoxOrganisation.Text = store.Organisation; _storeId = value; } catch (Exception ex) @@ -48,6 +50,11 @@ public partial class FormStore : Form throw new Exception("Адрес магазина не указан."); } + if (string.IsNullOrWhiteSpace(textBoxOrganisation.Text)) + { + throw new Exception("Организация магазина не указана."); + } + // Сохранение данных if (_storeId.HasValue) { @@ -74,6 +81,6 @@ public partial class FormStore : Form private Store CreateStore(int id) { // Создание сущности Store - return Store.CreateEntity(id, textBoxAddress.Text); + return Store.CreateEntity(id, textBoxAddress.Text, textBoxOrganisation.Text); } } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStores.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStores.cs index 9781d27..d5d0534 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStores.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormStores.cs @@ -88,6 +88,8 @@ public partial class FormStores : Form { // Загрузка списка магазинов в DataGridView dataGridViewStores.DataSource = _storeRepository.ReadStores().ToList(); + dataGridViewStores.Columns["Id"].Visible = false; + dataGridViewStores.Columns["FullInformation"].Visible = false; } private bool TryGetIdentifierFromSelectedRow(out int id) diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupplies.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupplies.cs index b49b261..285301e 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupplies.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupplies.cs @@ -44,6 +44,8 @@ public partial class FormSupplies : Form { // Загрузка списка поставок в DataGridView dataGridViewSupplies.DataSource = _supplyRepository.ReadSupplies().ToList(); + dataGridViewSupplies.Columns["Id"].Visible = false; + dataGridViewSupplies.Columns["OperationDate"].DefaultCellStyle.Format = "dd.MM.yyyy"; } private void ButtonDel_Click(object sender, EventArgs e) diff --git a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupply.cs b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupply.cs index b479f61..c71e9d5 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupply.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Forms/FormSupply.cs @@ -18,12 +18,12 @@ public partial class FormSupply : Form // Инициализация ComboBox для магазинов comboBoxStore.DataSource = _storeRepository.ReadStores().ToList(); - comboBoxStore.DisplayMember = "Address"; + comboBoxStore.DisplayMember = "FullInformation"; comboBoxStore.ValueMember = "Id"; // Инициализация ComboBox для товаров comboBoxProduct.DataSource = _productRepository.ReadProducts().ToList(); - comboBoxProduct.DisplayMember = "Name"; + comboBoxProduct.DisplayMember = "Type"; comboBoxProduct.ValueMember = "Id"; // Устанавливаем дату как текущую и блокируем редактирование diff --git a/ProjectOpticsStore/ProjectOpticsStore/ProjectOpticsStore.csproj b/ProjectOpticsStore/ProjectOpticsStore/ProjectOpticsStore.csproj index e5c4465..f9af576 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/ProjectOpticsStore.csproj +++ b/ProjectOpticsStore/ProjectOpticsStore/ProjectOpticsStore.csproj @@ -15,6 +15,7 @@ + diff --git a/ProjectOpticsStore/ProjectOpticsStore/Reports/ChartReport.cs b/ProjectOpticsStore/ProjectOpticsStore/Reports/ChartReport.cs index eee703f..c2b2f11 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Reports/ChartReport.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Reports/ChartReport.cs @@ -1,48 +1,72 @@ using Microsoft.Extensions.Logging; using ProjectOpticsStore.Repositories; +using ProjectOpticsStore.Entities; +using ProjectOpticsStore.Entities.Enums; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace ProjectOpticsStore.Reports; - -public class ChartReport +namespace ProjectOpticsStore.Reports { - private readonly ISupplyRepository _supplyRepository; // Изменение типа репозитория - private readonly ILogger _logger; - - public ChartReport(ISupplyRepository supplyRepository, ILogger logger) // Изменение параметра конструктора + public class ChartReport { - _supplyRepository = supplyRepository ?? throw new ArgumentNullException(nameof(supplyRepository)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + private readonly ISupplyRepository _supplyRepository; // Репозиторий для поставок + private readonly IProductRepository _productRepository; // Репозиторий для продуктов + private readonly ILogger _logger; - public bool CreateChart(string filePath, DateTime dateTime) - { - try + // Конструктор с зависимостями + public ChartReport(ISupplyRepository supplyRepository, IProductRepository productRepository, ILogger logger) { - new PdfBuilder(filePath) - .AddHeader("Распределение поставок по товарам") // Изменено заголовок для соответствия Supply - .AddPieChart("Поставки", GetData(dateTime)) // Изменено название графика - .Build(); - return true; + _supplyRepository = supplyRepository ?? throw new ArgumentNullException(nameof(supplyRepository)); + _productRepository = productRepository ?? throw new ArgumentNullException(nameof(productRepository)); // Для получения типа продукта + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка при формировании документа"); - return false; - } - } - private List<(string Caption, double Value)> GetData(DateTime dateTime) - { - return _supplyRepository - .ReadSupplies() // Изменено на метод, который читает поставки - .Where(x => x.OperationDate.Date == dateTime.Date) // Используем OperationDate вместо DateCreated - .GroupBy(x => x.ProductId, (key, group) => new { ID = key, TotalQuantity = group.Sum(y => y.Quantity) }) // Группировка по ProductId - .Select(x => (x.ID.ToString(), (double)x.TotalQuantity)) // Изменено на TotalQuantity - .ToList(); + // Метод для создания графика + public bool CreateChart(string filePath, DateTime dateTime) + { + try + { + // Создание PDF с графиком + new PdfBuilder(filePath) + .AddHeader("Распределение поставок по товарам") // Заголовок + .AddPieChart($"Поставки на {dateTime:dd MMMM yyyy}", GetData(dateTime)) // График + .Build(); + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка при формировании документа"); + return false; + } + } + + // Метод для получения данных для графика + private List<(string Caption, double Value)> GetData(DateTime dateTime) + { + // Получаем все поставки для заданной даты + var supplies = _supplyRepository + .ReadSupplies() + .Where(x => x.OperationDate.Date == dateTime.Date) // Фильтруем по дате + .GroupBy(x => x.ProductId) // Группируем по ProductId + .Select(g => new + { + ProductId = g.Key, + TotalQuantity = g.Sum(x => x.Quantity) + }) + .ToList(); + + // Для каждого ProductId находим тип товара через репозиторий продуктов + return supplies + .Select(x => + { + var product = _productRepository.ReadProductById(x.ProductId); // Получаем продукт по ProductId + var productType = product.Type.ToString(); // Получаем тип товара (ProductTypeEnum) + return (productType, (double)x.TotalQuantity); // Возвращаем тип товара и общее количество + }) + .ToList(); + } } } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Reports/DocReport.cs b/ProjectOpticsStore/ProjectOpticsStore/Reports/DocReport.cs index 1de3d8e..f008817 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Reports/DocReport.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Reports/DocReport.cs @@ -29,7 +29,7 @@ public class DocReport } if (includeStores) { - builder.AddParagraph("Магазины").AddTable([2400], GetStores()); + builder.AddParagraph("Магазины").AddTable([2400, 2400], GetStores()); } if (includeProducts) { @@ -58,10 +58,10 @@ public class DocReport private List GetStores() { return [ - ["Адрес магазина"], + ["Адрес магазина", "Организация"], .. _storeRepository .ReadStores() - .Select(x => new string[] { x.Address}), + .Select(x => new string[] { x.Address, x.Organisation}), ]; } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Reports/TableReport.cs b/ProjectOpticsStore/ProjectOpticsStore/Reports/TableReport.cs index 397c4a8..787eaa0 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Reports/TableReport.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Reports/TableReport.cs @@ -1,5 +1,9 @@ -using Microsoft.Extensions.Logging; +using DocumentFormat.OpenXml.Wordprocessing; +using Microsoft.Extensions.Logging; using ProjectOpticsStore.Repositories; +using System; +using System.Collections.Generic; +using System.Linq; namespace ProjectOpticsStore.Reports; @@ -8,7 +12,12 @@ public class TableReport private readonly IOrderRepository _orderRepository; private readonly ISupplyRepository _supplyRepository; private readonly ILogger _logger; - internal static readonly string[] item = ["Продукт", "Дата", "Количество пришло", "Количество ушло"]; + + // Заголовки таблицы + // Типо Order - заказ - количество ушло - заказчик, Поставка - количество пришло - магазин. + // Поэтому в первой строчке Заказчик/Магазин а не только Заказчик. Все согласно Ерке. + + internal static readonly string[] item = { "Заказчик", "Магазин", "Дата", "Количество пришло", "Количество ушло" }; public TableReport(IOrderRepository orderRepository, ISupplyRepository supplyRepository, ILogger logger) @@ -17,15 +26,22 @@ public class TableReport _supplyRepository = supplyRepository ?? throw new ArgumentNullException(nameof(supplyRepository)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + + // Метод для создания таблицы public bool CreateTable(string filePath, int productID, DateTime startDate, DateTime endDate) { try { + // Получение данных + var data = GetData(productID, startDate, endDate); + + // Создание Excel документа new ExcelBuilder(filePath) - .AddHeader("Сводка по движению товара", 0, 4) - .AddParagraph("за период", 0) - .AddTable([10, 10, 15, 15], GetData(productID, startDate, endDate)) - .Build(); + .AddHeader("Сводка по движению товаров", 0, 4) + .AddParagraph($"За период c {startDate:dd.MM.yyyy} по {endDate:dd.MM.yyyy}", 0) + .AddTable(new[] { 15, 15, 12, 15, 15 }, data) // Ширины столбцов + .Build(); + return true; } catch (Exception ex) @@ -35,47 +51,49 @@ public class TableReport } } - private List GetData(int productID, DateTime startDate, DateTime endDate) + // Метод для получения данных + private List GetData(int productId, DateTime startDate, DateTime endDate) { - var data = _orderRepository - .ReadOrders() - .Where(x => x.DateCreated >= startDate && x.DateCreated <= endDate && x.OrderProducts.Any(y => y.ProductId == productID)) - .Select(x => new + // Получение данных заказов + var ordersData = _orderRepository + .ReadOrders(dateFrom: startDate, dateTo: endDate, productId: productId) + .Select(order => new { - ProductID = x.OrderProducts.First(y => y.ProductId == productID).ProductId, - Date = x.DateCreated, + CustomerName = order.CustomerName, + StoreName = string.Empty, // Магазин не указывается для заказов + Date = order.DateCreated, CountIn = (int?)null, - CountOut = (int?)x.OrderProducts.FirstOrDefault(y => y.ProductId == productID)?.Quantity - }) - .Union( - _supplyRepository - .ReadSupplies() - .Where(x => x.OperationDate >= startDate && x.OperationDate <= endDate && x.ProductId == productID) - .Select(x => new - { - ProductID = x.ProductId, - Date = x.OperationDate, - CountIn = (int?)x.Quantity, - CountOut = (int?)null - })) + CountOut = (int?)order.OrderProducts.Sum(op => op.Quantity) + }); + + // Получение данных поставок + var suppliesData = _supplyRepository + .ReadSupplies(dateFrom: startDate, dateTo: endDate, productId: productId) + .Select(supply => new + { + CustomerName = string.Empty, // Заказчик не указывается для поставок + StoreName = supply.StoreName, + Date = supply.OperationDate, + CountIn = (int?)supply.Quantity, + CountOut = (int?)null + }); + + // Объединение и сортировка данных + var combinedData = ordersData + .Union(suppliesData) .OrderBy(x => x.Date); - return - new List { TableReport.item } + // Формирование таблицы + return new List { item } // Добавляем заголовок таблицы .Union( - data.Select(x => new string[] - { - x.ProductID.ToString(), - x.Date.ToString(), - x.CountIn?.ToString() ?? string.Empty, - x.CountOut?.ToString() ?? string.Empty - })) - .Union(new[] { - new[] { "Всего", "", data.Sum(x => x.CountIn ?? 0).ToString(), data.Sum(x => x.CountOut ?? 0).ToString() } + combinedData.Select(entry => new string[] {entry.CustomerName ?? string.Empty, entry.StoreName ?? string.Empty, entry.Date.ToString("dd.MM.yyyy"), entry.CountIn?.ToString("N0") ?? string.Empty, entry.CountOut?.ToString("N0") ?? string.Empty + }) + ) + .Union(new[] + { + // Итоговая строка + new string[] { "Всего", "", "", combinedData.Sum(entry => entry.CountIn ?? 0).ToString("N0"), combinedData.Sum(entry => entry.CountOut ?? 0).ToString("N0")} }) .ToList(); } } - - - diff --git a/ProjectOpticsStore/ProjectOpticsStore/Repositories/IOrderRepository.cs b/ProjectOpticsStore/ProjectOpticsStore/Repositories/IOrderRepository.cs index 033960c..329141d 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Repositories/IOrderRepository.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Repositories/IOrderRepository.cs @@ -5,7 +5,8 @@ public interface IOrderRepository IEnumerable ReadOrders( DateTime? dateFrom = null, DateTime? dateTo = null, - int? customerId = null + int? customerId = null, + int? productId = null ); void CreateOrder(Order order); } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/OrderRepository.cs b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/OrderRepository.cs index 37e3a94..5591d4b 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/OrderRepository.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/OrderRepository.cs @@ -1,8 +1,11 @@ using Dapper; +using DocumentFormat.OpenXml.Wordprocessing; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Npgsql; using ProjectOpticsStore.Entities; +using ProjectOpticsStore.Entities.Enums; using Unity; namespace ProjectOpticsStore.Repositories.Implementations; @@ -51,32 +54,77 @@ internal class OrderRepository : IOrderRepository } } - public IEnumerable ReadOrders(DateTime? dateFrom = null, DateTime? dateTo = null, int? productId = null) + public IEnumerable ReadOrders(DateTime? dateFrom = null, DateTime? dateTo = null, int? customerId = null, int? productId = null) { _logger.LogInformation("Получение всех объектов"); + try { + var builder = new QueryBuilder(); + + if (dateFrom.HasValue) + { + builder.AddCondition("o.DateCreated >= @dateFrom"); + } + if (dateTo.HasValue) + { + builder.AddCondition("o.DateCreated <= @dateTo"); + } + if (customerId.HasValue) + { + builder.AddCondition("o.CustomerId = @customerId"); + } + if (productId.HasValue) + { + builder.AddCondition("op.ProductId = @productId"); + } + using var connection = new NpgsqlConnection(_connectionString.ConnectionString); - var querySelect = @"SELECT o.*, op.OrderId, op.ProductId, op.Quantity - FROM Orders o - INNER JOIN Orders_Products op ON op.OrderId = o.Id"; + var querySelect = $@" + SELECT o.Id, + o.DateCreated, + o.Status, + c.FullName AS CustomerName, + os.Name AS StatusName, + p.Id AS ProductId, + p.Type AS Type, + op.Quantity + FROM Orders o + LEFT JOIN Customers c ON c.Id = o.CustomerId + LEFT JOIN OrderStatus os ON os.Id = o.Status + INNER JOIN Orders_Products op ON op.OrderId = o.Id + LEFT JOIN Products p ON p.Id = op.ProductId + + {builder.Build()}"; _logger.LogDebug("Выполняется SQL-запрос: {Query}", querySelect); - var orderProducts = connection.Query(querySelect); + var orderDict = new Dictionary>(); - _logger.LogDebug("Полученные объекты: {json}", JsonConvert.SerializeObject(orderProducts)); + var orders = connection.Query(querySelect, + (order, orderProduct) => + { + if (!orderDict.TryGetValue(order.Id, out var products)) + { + products = new List(); + orderDict.Add(order.Id, products); + } - return orderProducts - .GroupBy( - x => x.Id, - y => y, - (key, value) => Order.CreateOperation( - value.First(), - value.Select(z => Order_Product.CreateElement(z.OrderId, z.ProductId, z.Quantity)) - ) - ).ToList(); + products.Add(Order_Product.CreateElement(order.Id, orderProduct.ProductId, orderProduct.Type, orderProduct.Quantity)); + return order; + }, + splitOn: "ProductId", + param: new { dateFrom, dateTo, customerId, productId }); + + _logger.LogDebug("Полученные объекты: {json}", JsonConvert.SerializeObject(orders)); + + return orderDict.Select(x => + { + var order = orders.First(y => y.Id == x.Key); + order.SetOrderProducts(x.Value); + return order; + }).ToArray(); } catch (Exception ex) { diff --git a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/QueryBuilder.cs b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/QueryBuilder.cs new file mode 100644 index 0000000..fa7ee8c --- /dev/null +++ b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/QueryBuilder.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectOpticsStore.Repositories.Implementations; + +internal class QueryBuilder +{ + private readonly StringBuilder _builder; + public QueryBuilder() + { + _builder = new(); + } + public QueryBuilder AddCondition(string condition) + { + if (_builder.Length > 0) + { + _builder.Append(" AND "); + } + _builder.Append(condition); + return this; + } + public string Build() + { + if (_builder.Length == 0) + { + return string.Empty; + } + return $"WHERE {_builder}"; + } +} \ No newline at end of file diff --git a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/StoreRepository.cs b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/StoreRepository.cs index d59b7b3..f0aae94 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/StoreRepository.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/StoreRepository.cs @@ -24,8 +24,8 @@ internal class StoreRepository : IStoreRepository { using var connection = new NpgsqlConnection(_connectionString.ConnectionString); var queryInsert = @" - INSERT INTO Stores (Address) - VALUES (@Address)"; + INSERT INTO Stores (Address, Organisation) + VALUES (@Address, @Organisation)"; connection.Execute(queryInsert, store); } catch (Exception ex) @@ -44,7 +44,8 @@ internal class StoreRepository : IStoreRepository var queryUpdate = @" UPDATE Stores SET - Address=@Address + Address=@Address, + Organisation=@Organisation WHERE Id=@Id"; connection.Execute(queryUpdate, store); } diff --git a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/SupplyRepository.cs b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/SupplyRepository.cs index 0857614..731de31 100644 --- a/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/SupplyRepository.cs +++ b/ProjectOpticsStore/ProjectOpticsStore/Repositories/Implementations/SupplyRepository.cs @@ -1,9 +1,12 @@ using Dapper; using DocumentFormat.OpenXml.Office2010.Excel; +using DocumentFormat.OpenXml.Presentation; +using DocumentFormat.OpenXml.Wordprocessing; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Npgsql; using ProjectOpticsStore.Entities; +using System.Windows.Forms; namespace ProjectOpticsStore.Repositories.Implementations; @@ -60,12 +63,51 @@ internal class SupplyRepository : ISupplyRepository public IEnumerable ReadSupplies(DateTime? dateFrom = null, DateTime? dateTo = null, int? storeId = null, int? productId = null) { _logger.LogInformation("Получение всех объектов"); + try { + var builder = new QueryBuilder(); + + if (dateFrom.HasValue) + { + builder.AddCondition("su.OperationDate >= @dateFrom"); + } + if (dateTo.HasValue) + { + builder.AddCondition("su.OperationDate <= @dateTo"); + } + if (storeId.HasValue) + { + builder.AddCondition("su.StoreId = @storeId"); + } + if (productId.HasValue) + { + builder.AddCondition("su.ProductId = @productId"); + } + using var connection = new NpgsqlConnection(_connectionString.ConnectionString); - var querySelect = "SELECT * FROM Supplies"; - var supplies = connection.Query(querySelect); + + var querySelect = $@" + SELECT + su.*, + --p.Type AS ProductName, + TRIM( + CASE WHEN p.Type & 1 <> 0 THEN 'Очки, ' ELSE '' END || + CASE WHEN p.Type & 2 <> 0 THEN 'Контактные линзы, ' ELSE '' END || + CASE WHEN p.Type & 4 <> 0 THEN 'Солнцезащитные очки, ' ELSE '' END || + CASE WHEN p.Type & 8 <> 0 THEN 'Оправа, ' ELSE '' END || + CASE WHEN p.Type & 16 <> 0 THEN 'Футляры, ' ELSE '' END + , ', ') AS ProductName, + CONCAT(s.Address, ' ', s.Organisation) AS StoreName + FROM Supplies su + LEFT JOIN Products p ON p.Id = su.ProductId + LEFT JOIN Stores s ON s.Id = su.StoreId + {builder.Build()}"; + + var supplies = connection.Query(querySelect, new { dateFrom, dateTo, storeId, productId }); + _logger.LogDebug("Полученные объекты: {json}", JsonConvert.SerializeObject(supplies)); + return supplies; } catch (Exception ex)