using ChudoObuv.Logic; using ChudoObuv.Models; using MySqlConnector; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Runtime.InteropServices.JavaScript.JSType; namespace ChudoObuv.Data { /// /// Все запросы приложения к базе данных. /// public static class DataService { // ---------------------------- Пользователи ---------------------------- public static User FindUserByLogin(string login) { const string sql = @" SELECT u.user_id, u.last_name, u.first_name, u.patronymic, u.login, r.role_name FROM users u JOIN roles r ON r.role_id = u.role_id WHERE u.login = @login"; using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand(sql, connection); command.Parameters.AddWithValue("@login", login); using MySqlDataReader reader = command.ExecuteReader(); return reader.Read() ? ReadUser(reader) : null; } public static List GetClients() { const string sql = @" SELECT u.user_id, u.last_name, u.first_name, u.patronymic, u.login, r.role_name FROM users u JOIN roles r ON r.role_id = u.role_id WHERE r.role_name = @role ORDER BY u.last_name, u.first_name"; List clients = new List(); using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand(sql, connection); command.Parameters.AddWithValue("@role", User.ClientRole); using MySqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { clients.Add(ReadUser(reader)); } return clients; } private static User ReadUser(MySqlDataReader reader) { return new User { Id = reader.GetInt32("user_id"), LastName = reader.GetString("last_name"), FirstName = reader.GetString("first_name"), Patronymic = reader.IsDBNull(reader.GetOrdinal("patronymic")) ? "" : reader.GetString("patronymic"), Login = reader.GetString("login"), Role = reader.GetString("role_name") }; } // ------------------------------- Товары ------------------------------- public static List GetProducts() { const string sql = @" SELECT p.product_id, p.product_name, c.category_name, s.subcategory_name,m.manufacture_name,p.description, p.composition, p.price, p.image_file, COALESCE((SELECT SUM(si.quantity) FROM stock_items si WHERE si.product_id = p.product_id), 0) AS total_quantity, EXISTS (SELECT 1 FROM order_items oi JOIN orders o ON o.order_id = oi.order_id JOIN stock_items si ON si.stock_item_id = oi.stock_item_id WHERE si.product_id = p.product_id AND o.order_date >= @previousMonthStart AND o.order_date < @currentMonthStart) AS has_previous_month_orders FROM products p JOIN categories c ON c.category_id = p.category_id JOIN subcategories s ON s.subcategory_id = p.subcategory_id JOIN manufacturers m ON m.manufacture_id = p.manufacturer_id ORDER BY p.product_id"; DateTime today = DateTime.Today; List products = new List(); using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand(sql, connection); command.Parameters.AddWithValue("@previousMonthStart", PriceCalculator.GetPreviousMonthStart(today)); command.Parameters.AddWithValue("@currentMonthStart", PriceCalculator.GetCurrentMonthStart(today)); using MySqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { products.Add(new Product { Id = reader.GetInt32("product_id"), Name = reader.GetString("product_name"), Category = reader.GetString("category_name"), Subcategory = reader.GetString("subcategory_name"), Manufacturer = reader.GetString("manufacture_name"), Description = reader.IsDBNull(reader.GetOrdinal("description")) ? "" : reader.GetString("description"), Composition = reader.IsDBNull(reader.GetOrdinal("composition")) ? "" : reader.GetString("composition"), Price = reader.GetDecimal("price"), ImageFile = reader.IsDBNull(reader.GetOrdinal("image_file")) ? null : reader.GetString("image_file"), TotalQuantity = Convert.ToInt32(reader["total_quantity"]), HasOrdersInPreviousMonth = Convert.ToInt32(reader["has_previous_month_orders"]) == 1 }); } return products; } public static List GetCategories() { List categories = new List(); using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand("SELECT category_name FROM categories ORDER BY category_name", connection); using MySqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { categories.Add(reader.GetString(0)); } return categories; } /// /// Все товарные позиции модели (размерный ряд) с доступным количеством. /// public static List GetStockItems(int productId) { const string sql = @" SELECT si.stock_item_id, si.product_id, s.size_value, si.quantity FROM stock_items si JOIN sizes s ON s.size_id = si.size_id WHERE si.product_id = @productId ORDER BY s.size_value"; List items = new List(); using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand(sql, connection); command.Parameters.AddWithValue("@productId", productId); using MySqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { items.Add(new StockItem { Id = reader.GetInt32("stock_item_id"), ProductId = reader.GetInt32("product_id"), Size = reader.GetDecimal("size_value"), Quantity = reader.GetInt32("quantity") }); } return items; } // ------------------------------- Заказы ------------------------------- public static List GetOrders() { const string sql = @" SELECT o.order_id, o.order_date, u.user_id, CONCAT_WS(' ', u.last_name, u.first_name, u.patronymic) AS client_name, COUNT(oi.order_item_id) AS items_count, COALESCE(SUM(oi.quantity * oi.unit_price), 0) AS total_sum FROM orders o JOIN users u ON u.user_id = o.user_id LEFT JOIN order_items oi ON oi.order_id = o.order_id GROUP BY o.order_id, o.order_date, u.user_id, client_name ORDER BY o.order_date DESC, o.order_id DESC"; List orders = new List(); using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand(sql, connection); using MySqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { orders.Add(new Order { Id = reader.GetInt32("order_id"), OrderDate = reader.GetDateTime("order_date"), ClientId = reader.GetInt32("user_id"), ClientFullName = reader.GetString("client_name"), ItemsCount = Convert.ToInt32(reader["items_count"]), TotalSum = reader.GetDecimal("total_sum") }); } return orders; } public static List GetOrderItems(int orderId) { const string sql = @" SELECT oi.order_item_id, oi.stock_item_id, p.product_name, m.manufacturer_name, s.size_value, oi.quantity, oi.unit_price FROM order_items oi JOIN stock_items si ON si.stock_item_id = oi.stock_item_id JOIN products p ON p.product_id = si.product_id JOIN manufacturers m ON m.manufacturer_id = p.manufacturer_id JOIN sizes s ON s.size_id = si.size_id WHERE oi.order_id = @orderId ORDER BY oi.order_item_id"; List items = new List(); using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand(sql, connection); command.Parameters.AddWithValue("@orderId", orderId); using MySqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { items.Add(new OrderItem { Id = reader.GetInt32("order_item_id"), StockItemId = reader.GetInt32("stock_item_id"), ProductName = reader.GetString("product_name"), Manufacturer = reader.GetString("manufacturer_name"), Size = reader.GetDecimal("size_value"), Quantity = reader.GetInt32("quantity"), UnitPrice = reader.GetDecimal("unit_price") }); } return items; } /// /// Сохраняет заказ и уменьшает остатки. Возвращает номер заказа. /// Если какого-то размера уже не хватает — заказ не сохраняется (исключение). /// public static int CreateOrder(int clientId, List items) { using MySqlConnection connection = Database.OpenConnection(); using MySqlTransaction transaction = connection.BeginTransaction(); MySqlCommand orderCommand = new MySqlCommand( "INSERT INTO orders (order_date, user_id) VALUES (@date, @userId)", connection, transaction); orderCommand.Parameters.AddWithValue("@date", DateTime.Today); orderCommand.Parameters.AddWithValue("@userId", clientId); orderCommand.ExecuteNonQuery(); int orderId = (int)orderCommand.LastInsertedId; foreach (OrderItem item in items) { // Остаток уменьшается только если его хватает — защита от одновременных заказов MySqlCommand stockCommand = new MySqlCommand( "UPDATE stock_items SET quantity = quantity - @quantity WHERE stock_item_id = @id AND quantity >= @quantity", connection, transaction); stockCommand.Parameters.AddWithValue("@quantity", item.Quantity); stockCommand.Parameters.AddWithValue("@id", item.StockItemId); if (stockCommand.ExecuteNonQuery() == 0) { transaction.Rollback(); throw new InvalidOperationException( $"Недостаточно товара «{item.ProductName}», размер {item.SizeText}. Обновите каталог и измените количество."); } MySqlCommand itemCommand = new MySqlCommand( "INSERT INTO order_items (order_id, stock_item_id, quantity, unit_price) VALUES (@orderId, @stockItemId, @quantity, @price)", connection, transaction); itemCommand.Parameters.AddWithValue("@orderId", orderId); itemCommand.Parameters.AddWithValue("@stockItemId", item.StockItemId); itemCommand.Parameters.AddWithValue("@quantity", item.Quantity); itemCommand.Parameters.AddWithValue("@price", item.UnitPrice); itemCommand.ExecuteNonQuery(); } transaction.Commit(); return orderId; } /// /// Удаляет заказ и возвращает его товары на склад. /// public static void DeleteOrder(int orderId) { using MySqlConnection connection = Database.OpenConnection(); using MySqlTransaction transaction = connection.BeginTransaction(); MySqlCommand returnCommand = new MySqlCommand(@" UPDATE stock_items si JOIN order_items oi ON oi.stock_item_id = si.stock_item_id SET si.quantity = si.quantity + oi.quantity WHERE oi.order_id = @orderId", connection, transaction); returnCommand.Parameters.AddWithValue("@orderId", orderId); returnCommand.ExecuteNonQuery(); // Строки состава удаляются каскадно (ON DELETE CASCADE) MySqlCommand deleteCommand = new MySqlCommand("DELETE FROM orders WHERE order_id = @orderId", connection, transaction); deleteCommand.Parameters.AddWithValue("@orderId", orderId); deleteCommand.ExecuteNonQuery(); transaction.Commit(); } /// /// Удаляет товарную позицию из заказа и возвращает ее количество на склад. /// public static void DeleteOrderItem(int orderItemId) { using MySqlConnection connection = Database.OpenConnection(); using MySqlTransaction transaction = connection.BeginTransaction(); MySqlCommand returnCommand = new MySqlCommand(@" UPDATE stock_items si JOIN order_items oi ON oi.stock_item_id = si.stock_item_id SET si.quantity = si.quantity + oi.quantity WHERE oi.order_item_id = @id", connection, transaction); returnCommand.Parameters.AddWithValue("@id", orderItemId); returnCommand.ExecuteNonQuery(); MySqlCommand deleteCommand = new MySqlCommand("DELETE FROM order_items WHERE order_item_id = @id", connection, transaction); deleteCommand.Parameters.AddWithValue("@id", orderItemId); deleteCommand.ExecuteNonQuery(); transaction.Commit(); } public static void UpdateOrderDate(int orderId, DateTime orderDate) { using MySqlConnection connection = Database.OpenConnection(); using MySqlCommand command = new MySqlCommand("UPDATE orders SET order_date = @date WHERE order_id = @orderId", connection); command.Parameters.AddWithValue("@date", orderDate.Date); command.Parameters.AddWithValue("@orderId", orderId); command.ExecuteNonQuery(); } } }