diff --git a/ChudoObuv.slnx b/ChudoObuv.slnx
new file mode 100644
index 0000000..63afa36
--- /dev/null
+++ b/ChudoObuv.slnx
@@ -0,0 +1,3 @@
+
+
+
diff --git a/ChudoObuv/App.xaml b/ChudoObuv/App.xaml
new file mode 100644
index 0000000..b7fc699
--- /dev/null
+++ b/ChudoObuv/App.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/App.xaml.cs b/ChudoObuv/App.xaml.cs
new file mode 100644
index 0000000..65deaf6
--- /dev/null
+++ b/ChudoObuv/App.xaml.cs
@@ -0,0 +1,32 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+using System.Globalization;
+using System.Windows.Markup;
+using System.Windows.Threading;
+using ChudoObuv.Logic;
+
+namespace ChudoObuv
+{
+ public partial class App : Application
+ {
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ // Русский формат чисел, цен и дат во всем приложении (в том числе в привязках XAML)
+ CultureInfo russian = new CultureInfo("ru-RU");
+ CultureInfo.DefaultThreadCurrentCulture = russian;
+ CultureInfo.DefaultThreadCurrentUICulture = russian;
+ Thread.CurrentThread.CurrentCulture = russian;
+ Thread.CurrentThread.CurrentUICulture = russian;
+ FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
+ new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(russian.IetfLanguageTag)));
+ base.OnStartup(e);
+ }
+ // Последняя защита от аварийного завершения: любая необработанная ошибка показывается пользователю
+ private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
+ {
+ Messages.ShowError($"Произошла непредвиденная ошибка: {e.Exception.Message}\nПовторите действие.Если ошибка повторяется, перезапустите приложение.");
+ e.Handled = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/AssemblyInfo.cs b/ChudoObuv/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/ChudoObuv/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/ChudoObuv/ChudoObuv.csproj b/ChudoObuv/ChudoObuv.csproj
new file mode 100644
index 0000000..35714f5
--- /dev/null
+++ b/ChudoObuv/ChudoObuv.csproj
@@ -0,0 +1,24 @@
+
+
+
+ WinExe
+ net8.0-windows
+ disable
+ enable
+ true
+ Resources\app.ico
+ Чудо Обувь
+ Чудо Обувь
+ Чудо Обувь
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Data/DataService.cs b/ChudoObuv/Data/DataService.cs
new file mode 100644
index 0000000..785e432
--- /dev/null
+++ b/ChudoObuv/Data/DataService.cs
@@ -0,0 +1,321 @@
+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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Data/Database.cs b/ChudoObuv/Data/Database.cs
new file mode 100644
index 0000000..ad82d44
--- /dev/null
+++ b/ChudoObuv/Data/Database.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MySqlConnector;
+
+namespace ChudoObuv.Data
+{
+ ///
+ /// Подключение к базе данных MySQL.
+ ///
+ public static class Database
+ {
+ // Перед запуском укажите свои сервер, имя базы, пользователя и пароль MySQL
+ private const string ConnectionString = "Server=177.1.181.207;Port=3306;Database=isp-41_lipatova_yuv_chudo_obuv;UserID=isp-41_lipatova_yuv;Password=isp-41_lipatova_yuv;CharSet=utf8mb4;";
+ public static MySqlConnection OpenConnection()
+ {
+ MySqlConnection connection = new MySqlConnection(ConnectionString);
+ connection.Open();
+ return connection;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Logic/Messages.cs b/ChudoObuv/Logic/Messages.cs
new file mode 100644
index 0000000..a3d1e45
--- /dev/null
+++ b/ChudoObuv/Logic/Messages.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using MySqlConnector;
+
+namespace ChudoObuv.Logic
+{
+ ///
+ /// Окна сообщений с заголовком и пиктограммой нужного типа.
+ ///
+ public static class Messages
+
+
+{
+private const string AppName = "Чудо Обувь";
+ public static void ShowError(string text)
+ {
+ MessageBox.Show(text, $"{AppName} — Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ public static void ShowWarning(string text)
+ {
+ MessageBox.Show(text, $"{AppName} — Предупреждение", MessageBoxButton.OK,
+ MessageBoxImage.Warning);
+ }
+ public static void ShowInfo(string text)
+ {
+ MessageBox.Show(text, $"{AppName} — Информация", MessageBoxButton.OK,
+ MessageBoxImage.Information);
+ }
+ ///
+ /// Подтверждение необратимой операции. Возвращает true, если пользователь нажал «Да».
+ ///
+ public static bool Confirm(string text)
+ {
+ MessageBoxResult result = MessageBox.Show(text, $"{AppName} — Подтверждение",
+ MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
+ return result == MessageBoxResult.Yes;
+ }
+ public static void ShowDatabaseError(Exception exception)
+ {
+ if (exception is MySqlException)
+ {
+ ShowError("Не удалось выполнить операцию с базой данных.\n" +
+ $"Причина: {exception.Message}\n\n" +
+ "Проверьте, что сервер MySQL запущен, а в файле Data\\Database.cs указаны верные сервер, пользователь и пароль.");
+ }
+ else
+ {
+ ShowError(exception.Message);
+ }
+ }
+}
+}
\ No newline at end of file
diff --git a/ChudoObuv/Logic/PriceCalculator.cs b/ChudoObuv/Logic/PriceCalculator.cs
new file mode 100644
index 0000000..df8f533
--- /dev/null
+++ b/ChudoObuv/Logic/PriceCalculator.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ChudoObuv.Logic
+{
+ ///
+ /// Алгоритмы расчета показателей товара.
+ ///
+ public static class PriceCalculator
+ {
+ public const decimal DiscountPercent = 25m;
+ public const int ManyQuantityThreshold = 5;
+ public const int LowStockThreshold = 3;
+ ///
+ /// Начало предыдущего календарного месяца относительно даты расчета.
+ ///
+ public static DateTime GetPreviousMonthStart(DateTime calculationDate)
+ {
+ return GetCurrentMonthStart(calculationDate).AddMonths(-1);
+ }
+ public static DateTime GetCurrentMonthStart(DateTime calculationDate)
+ {
+ return new DateTime(calculationDate.Year, calculationDate.Month, 1);
+ }
+ ///
+ /// Цена со скидкой 25%, если в предыдущем календарном месяце заказов товара не было.
+ ///
+ public static decimal CalculateDiscountedPrice(decimal price, bool hasOrdersInPreviousMonth)
+ {
+ if (hasOrdersInPreviousMonth)
+ {
+ return price;
+ }
+ return Math.Round(price * (100m - DiscountPercent) / 100m, 2);
+ }
+ ///
+ /// «много», если пар больше пяти, иначе «мало».
+ ///
+ public static string GetQuantityLabel(int totalQuantity)
+ {
+ return totalQuantity > ManyQuantityThreshold ? "много" : "мало";
+ }
+ public static bool IsLowStock(int totalQuantity)
+ {
+ return totalQuantity <= LowStockThreshold;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Logic/Session.cs b/ChudoObuv/Logic/Session.cs
new file mode 100644
index 0000000..e25a9e6
--- /dev/null
+++ b/ChudoObuv/Logic/Session.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using ChudoObuv.Models;
+namespace ChudoObuv.Logic
+{
+ ///
+ /// Текущий пользователь и формируемый (еще не подтвержденный) заказ.
+ ///
+ public static class Session
+ {
+ public static User CurrentUser { get; private set; }
+ ///
+ /// Клиент, для которого формируется заказ: сам пользователь или клиент, выбранный менеджером.
+ ///
+ public static User OrderClient { get; private set; }
+ public static List Cart { get; } = new List();
+ public static bool IsAuthorized => CurrentUser != null;
+ public static void Login(User user)
+ {
+ CurrentUser = user;
+ OrderClient = user;
+ Cart.Clear();
+ }
+ public static void Logout()
+ {
+ CurrentUser = null;
+ OrderClient = null;
+ Cart.Clear();
+ }
+ public static void StartOrderFor(User client)
+ {
+ OrderClient = client;
+ Cart.Clear();
+ }
+ public static void CancelOrder()
+ {
+ Cart.Clear();
+ OrderClient = CurrentUser;
+ }
+ ///
+ /// Сколько пар данной товарной позиции уже лежит в формируемом заказе.
+ ///
+ public static int GetQuantityInCart(int stockItemId)
+ {
+ return Cart.Where(item => item.StockItemId == stockItemId).Sum(item => item.Quantity);
+ }
+ public static void AddToCart(OrderItem newItem)
+ {
+ OrderItem existing = Cart.FirstOrDefault(item => item.StockItemId == newItem.StockItemId);
+ if (existing != null)
+ {
+ existing.Quantity += newItem.Quantity;
+ }
+ else
+ {
+ Cart.Add(newItem);
+ }
+ }
+
+}
+}
\ No newline at end of file
diff --git a/ChudoObuv/MainWindow.xaml b/ChudoObuv/MainWindow.xaml
new file mode 100644
index 0000000..b8f153f
--- /dev/null
+++ b/ChudoObuv/MainWindow.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/MainWindow.xaml.cs b/ChudoObuv/MainWindow.xaml.cs
new file mode 100644
index 0000000..da04545
--- /dev/null
+++ b/ChudoObuv/MainWindow.xaml.cs
@@ -0,0 +1,79 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Navigation;
+using ChudoObuv.Logic;
+using ChudoObuv.Pages;
+
+namespace ChudoObuv
+{
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ MainFrame.Navigate(new LoginPage());
+ }
+ private void MainFrame_Navigated(object sender, NavigationEventArgs e)
+ {
+ // Заголовок окна и шапки берется из заголовка открытой страницы
+ if (e.Content is Page page)
+ {
+ Title = $"Чудо Обувь — {page.Title}";
+ PageTitleText.Text = page.Title;
+ }
+ BackButton.Visibility = MainFrame.CanGoBack ? Visibility.Visible : Visibility.Collapsed;
+ UpdateUserInfo();
+ }
+ private void UpdateUserInfo()
+ {
+ bool isLoginPage = MainFrame.Content is LoginPage;
+ if (Session.IsAuthorized)
+ {
+ UserNameText.Text = Session.CurrentUser.FullName;
+ UserRoleText.Text = Session.CurrentUser.Role;
+
+ LogoutButton.Content = "Выйти";
+ }
+ else
+ {
+ UserNameText.Text = isLoginPage ? "" : "Гость";
+ UserRoleText.Text = "";
+ LogoutButton.Content = "Войти";
+ }
+ LogoutButton.Visibility = isLoginPage ? Visibility.Collapsed : Visibility.Visible;
+ }
+ private void BackButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (MainFrame.CanGoBack)
+ {
+ MainFrame.GoBack();
+ }
+ }
+ private void LogoutButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (Session.Cart.Count > 0 && !Messages.Confirm("Неподтвержденный заказ будет отменен. Выйти из системы?"))
+ {
+ return;
+ }
+ Session.Logout();
+ MainFrame.Navigate(new LoginPage());
+ ClearHistory();
+ }
+ ///
+ /// Очищает историю переходов, чтобы кнопкой «Назад» нельзя было вернуться в чужой сеанс.
+ ///
+ public void ClearHistory()
+ {
+ // Навигация выполняется асинхронно, поэтому очищаем журнал после завершения перехода
+ Dispatcher.BeginInvoke(new Action(() =>
+ {
+ while (MainFrame.CanGoBack)
+ {
+ MainFrame.RemoveBackEntry();
+ }
+ BackButton.Visibility = Visibility.Collapsed;
+ UpdateUserInfo();
+ }), System.Windows.Threading.DispatcherPriority.ContextIdle);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Models/Order.cs b/ChudoObuv/Models/Order.cs
new file mode 100644
index 0000000..e2d2dc2
--- /dev/null
+++ b/ChudoObuv/Models/Order.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ChudoObuv.Models
+{
+ public class Order
+ {
+ public int Id { get; set; }
+ public DateTime OrderDate { get; set; }
+ public int ClientId { get; set; }
+ public string ClientFullName { get; set; }
+ public int ItemsCount { get; set; }
+ public decimal TotalSum { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Models/OrderItem.cs b/ChudoObuv/Models/OrderItem.cs
new file mode 100644
index 0000000..2acb979
--- /dev/null
+++ b/ChudoObuv/Models/OrderItem.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ChudoObuv.Models
+{
+ ///
+ /// Строка состава заказа (сохраненная в БД или в оформляемом заказе).
+ ///
+ public class OrderItem
+ {
+ public int Id { get; set; }
+ public int StockItemId { get; set; }
+ public string ProductName { get; set; }
+ public string Manufacturer { get; set; }
+ public decimal Size { get; set; }
+ public int Quantity { get; set; }
+ public decimal UnitPrice { get; set; }
+ public string Position => $"{ProductName}, {Manufacturer}, размер {Size:0.#}";
+ public string SizeText => Size.ToString("0.#");
+ public decimal Sum => UnitPrice * Quantity;
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Models/Product.cs b/ChudoObuv/Models/Product.cs
new file mode 100644
index 0000000..768d05c
--- /dev/null
+++ b/ChudoObuv/Models/Product.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
+using ChudoObuv.Logic;
+
+namespace ChudoObuv.Models
+{
+ ///
+ /// Товар (модель обуви) для вывода в каталоге.
+ ///
+ public class Product
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string Category { get; set; }
+ public string Subcategory { get; set; }
+ public string Manufacturer { get; set; }
+ public string Description { get; set; }
+ public string Composition { get; set; }
+ public decimal Price { get; set; }
+ public string ImageFile { get; set; }
+ public int TotalQuantity { get; set; }
+ public bool HasOrdersInPreviousMonth { get; set; }
+ public string Title => $"{Manufacturer} | {Name}";
+ public decimal DiscountedPrice => PriceCalculator.CalculateDiscountedPrice(Price,
+ HasOrdersInPreviousMonth);
+ public bool HasDiscount => DiscountedPrice < Price;
+ public string QuantityLabel => PriceCalculator.GetQuantityLabel(TotalQuantity);
+ public bool IsLowStock => PriceCalculator.IsLowStock(TotalQuantity);
+ ///
+ /// Путь к изображению товара; если файла нет — картинка-заглушка.
+ ///
+ public string ImagePath
+ {
+ get
+ {
+ string folder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources");
+ if (!string.IsNullOrWhiteSpace(ImageFile))
+ {
+ string path = Path.Combine(folder, "Images", ImageFile);
+
+ if (File.Exists(path))
+ {
+
+ return path;
+ }
+ }
+ return Path.Combine(folder, "picture.png");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Models/StockItem.cs b/ChudoObuv/Models/StockItem.cs
new file mode 100644
index 0000000..e345f89
--- /dev/null
+++ b/ChudoObuv/Models/StockItem.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ChudoObuv.Models
+{
+ ///
+ /// Товарная позиция: модель + размер с доступным количеством.
+ ///
+ public class StockItem
+ {
+ public int Id { get; set; }
+ public int ProductId { get; set; }
+ public decimal Size { get; set; }
+ public int Quantity { get; set; }
+ public string SizeText => Size.ToString("0.#");
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Models/User.cs b/ChudoObuv/Models/User.cs
new file mode 100644
index 0000000..1404efe
--- /dev/null
+++ b/ChudoObuv/Models/User.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ChudoObuv.Models
+{
+ public class User
+ {
+ public const string AdminRole = "Администратор";
+ public const string ManagerRole = "Менеджер";
+ public const string ClientRole = "Авторизованный пользователь";
+ public int Id { get; set; }
+ public string LastName { get; set; }
+ public string FirstName { get; set; }
+ public string Patronymic { get; set; }
+ public string Login { get; set; }
+ public string Role { get; set; }
+ public string FullName => $"{LastName} {FirstName} {Patronymic}".Trim();
+ public bool IsAdmin => Role == AdminRole;
+ public bool IsManagerOrAdmin => Role == ManagerRole || Role == AdminRole;
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Pages/CartPage.xaml b/ChudoObuv/Pages/CartPage.xaml
new file mode 100644
index 0000000..6d1405d
--- /dev/null
+++ b/ChudoObuv/Pages/CartPage.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Pages/CartPage.xaml.cs b/ChudoObuv/Pages/CartPage.xaml.cs
new file mode 100644
index 0000000..2a9dc3d
--- /dev/null
+++ b/ChudoObuv/Pages/CartPage.xaml.cs
@@ -0,0 +1,102 @@
+using ChudoObuv.Pages;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ChudoObuv.Data;
+using ChudoObuv.Logic;
+using ChudoObuv.Models;
+
+namespace ChudoObuv.Pages
+{
+ public partial class CartPage : Page
+ {
+ public CartPage()
+ {
+ InitializeComponent();
+ }
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ RefreshCart();
+ }
+ private void RefreshCart()
+ {
+ ClientText.Text = $"Клиент: {Session.OrderClient.FullName} Дата заказа: { DateTime.Today:dd.MM.yyyy}";
+ ItemsDataGrid.ItemsSource = null;
+ ItemsDataGrid.ItemsSource = Session.Cart;
+ TotalText.Text = $"Итого: {Session.Cart.Sum(item => item.Sum):N2} ₽";
+ }
+ private void RemoveItemButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (((Button)sender).DataContext is OrderItem item &&
+ Messages.Confirm($"Удалить из заказа «{item.ProductName}», размер {item.SizeText}?"))
+ {
+ Session.Cart.Remove(item);
+ RefreshCart();
+ }
+ }
+ private void ContinueButton_Click(object sender, RoutedEventArgs e)
+ {
+ NavigationService.Navigate(new CatalogPage());
+ }
+ private void CancelOrderButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (!Messages.Confirm("Отказаться от заказа? Все выбранные товары будут удалены из заказа. Действие нельзя отменить."))
+ {
+ return;
+ }
+ Session.CancelOrder();
+ GoHome();
+ }
+ private void ConfirmButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (Session.Cart.Count == 0)
+ {
+
+Messages.ShowWarning("В заказе нет товаров. Выберите товар в каталоге, укажите размер и количество и нажмите «Добавить в заказ».");
+ return;
+ }
+ if (!Messages.Confirm($"Подтвердить заказ на сумму {Session.Cart.Sum(item => item.Sum):N2} ₽для клиента { Session.OrderClient.FullName}?"))
+ {
+ return;
+ }
+ try
+ {
+ int orderId = DataService.CreateOrder(Session.OrderClient.Id, Session.Cart);
+ Messages.ShowInfo($"Заказ No {orderId} оформлен {DateTime.Today:dd.MM.yyyy}.");
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ return;
+ }
+ Session.CancelOrder();
+ GoHome();
+ }
+ ///
+ /// Менеджер и администратор возвращаются к списку заказов, клиент — в каталог.
+ ///
+ private void GoHome()
+ {
+ if (Session.CurrentUser.IsManagerOrAdmin)
+ {
+ NavigationService.Navigate(new OrdersPage());
+ }
+ else
+ {
+ NavigationService.Navigate(new CatalogPage());
+ }
+ ((MainWindow)Application.Current.MainWindow).ClearHistory();
+ }
+ }
+}
diff --git a/ChudoObuv/Pages/CatalogPage.xaml b/ChudoObuv/Pages/CatalogPage.xaml
new file mode 100644
index 0000000..748e3ef
--- /dev/null
+++ b/ChudoObuv/Pages/CatalogPage.xaml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Pages/CatalogPage.xaml.cs b/ChudoObuv/Pages/CatalogPage.xaml.cs
new file mode 100644
index 0000000..5518de7
--- /dev/null
+++ b/ChudoObuv/Pages/CatalogPage.xaml.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ChudoObuv.Data;
+using ChudoObuv.Logic;
+using ChudoObuv.Models;
+
+namespace ChudoObuv.Pages
+{
+ public partial class CatalogPage : Page
+ {
+ private const string AllCategories = "Все категории";
+ private List allProducts = new List();
+ private bool isInitialized;
+ public CatalogPage()
+ {
+ InitializeComponent();
+ }
+ // Вызывается при каждом открытии страницы, в том числе после возврата «Назад»,
+ // поэтому каталог и остатки всегда актуальны
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ bool isAuthorized = Session.IsAuthorized;
+ FilterPanel.Visibility = isAuthorized ? Visibility.Visible : Visibility.Collapsed;
+ CartButton.Visibility = isAuthorized ? Visibility.Visible : Visibility.Collapsed;
+ OrdersButton.Visibility = isAuthorized && Session.CurrentUser.IsManagerOrAdmin ?
+ Visibility.Visible : Visibility.Collapsed;
+ CartButton.Content = $"Оформление заказа ({Session.Cart.Sum(item => item.Quantity)})";
+ OrderClientText.Text = isAuthorized ? $"Заказ оформляется для клиента: {Session.OrderClient.FullName}" : "Для оформления заказа войдите в систему.";
+ try
+ {
+ if (!isInitialized)
+ {
+
+
+List categories = DataService.GetCategories();
+
+ categories.Insert(0, AllCategories);
+ CategoryComboBox.ItemsSource = categories;
+ CategoryComboBox.SelectedIndex = 0;
+ isInitialized = true;
+
+ }
+ allProducts = DataService.GetProducts();
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ allProducts = new List();
+ }
+ ApplyFilters();
+ }
+ private void Filter_Changed(object sender, EventArgs e)
+ {
+ ApplyFilters();
+ }
+ ///
+ /// Поиск, фильтр и сортировка применяются вместе при любом изменении.
+ ///
+ private void ApplyFilters()
+ {
+ if (ProductsListView == null || SortComboBox == null)
+ {
+ return;
+ }
+ IEnumerable result = allProducts;
+ if (Session.IsAuthorized)
+ {
+ string search = SearchTextBox.Text.Trim();
+ if (search.Length > 0)
+ {
+ result = result.Where(product =>
+ product.Name.Contains(search, StringComparison.OrdinalIgnoreCase) ||
+ product.Description.Contains(search, StringComparison.OrdinalIgnoreCase));
+
+ }
+ string category = CategoryComboBox.SelectedItem as string;
+ if (category != null && category != AllCategories)
+ {
+ result = result.Where(product => product.Category == category);
+ }
+ if (SortComboBox.SelectedIndex == 1)
+ {
+ result = result.OrderBy(product => product.DiscountedPrice);
+ }
+ else if (SortComboBox.SelectedIndex == 2)
+ {
+ result = result.OrderByDescending(product => product.DiscountedPrice);
+ }
+ }
+ List shown = result.ToList();
+ ProductsListView.ItemsSource = shown;
+ CountText.Text = $"Показано товаров: {shown.Count} из {allProducts.Count}";
+ }
+ private void ProductsListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (ProductsListView.SelectedItem is not Product product)
+ {
+ return;
+ }
+ ProductsListView.SelectedItem = null;
+ if (!Session.IsAuthorized)
+ {
+
+
+ Messages.ShowInfo("Оформлять заказы могут только авторизованные пользователи.\nВыйдите на страницу входа и войдите под своим логином.");
+ return;
+ }
+ NavigationService.Navigate(new ProductPage(product));
+ }
+ private void CartButton_Click(object sender, RoutedEventArgs e)
+ {
+ NavigationService.Navigate(new CartPage());
+ }
+ private void OrdersButton_Click(object sender, RoutedEventArgs e)
+ {
+ NavigationService.Navigate(new OrdersPage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Pages/LoginPage.xaml b/ChudoObuv/Pages/LoginPage.xaml
new file mode 100644
index 0000000..d528e50
--- /dev/null
+++ b/ChudoObuv/Pages/LoginPage.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Pages/LoginPage.xaml.cs b/ChudoObuv/Pages/LoginPage.xaml.cs
new file mode 100644
index 0000000..8834962
--- /dev/null
+++ b/ChudoObuv/Pages/LoginPage.xaml.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ChudoObuv.Data;
+using ChudoObuv.Logic;
+using ChudoObuv.Models;
+namespace ChudoObuv.Pages
+{
+ public partial class LoginPage : Page
+ {
+ public LoginPage()
+ {
+ InitializeComponent();
+ Loaded += (sender, e) => LoginTextBox.Focus();
+ }
+ private void LoginButton_Click(object sender, RoutedEventArgs e)
+ {
+ TryLogin();
+ }
+ private void LoginTextBox_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ {
+ TryLogin();
+ }
+ }
+ private void TryLogin()
+ {
+ string login = LoginTextBox.Text.Trim();
+ if (login.Length == 0)
+ {
+
+Messages.ShowWarning("Введите логин. Логин выдается администратором и указан в списке пользователей системы.");
+LoginTextBox.Focus();
+ return;
+ }
+ User user;
+ try
+ {
+ user = DataService.FindUserByLogin(login);
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ return;
+ }
+ if (user == null)
+ {
+ Messages.ShowError($"Пользователь с логином «{login}» не найден.\nПроверьте раскладку клавиатуры и правильность ввода логина или войдите как гость.");
+ LoginTextBox.SelectAll();
+ LoginTextBox.Focus();
+ return;
+ }
+ Session.Login(user);
+ OpenCatalog();
+ }
+ private void GuestButton_Click(object sender, RoutedEventArgs e)
+ {
+ Session.Logout();
+ OpenCatalog();
+ }
+ private void OpenCatalog()
+ {
+ NavigationService.Navigate(new CatalogPage());
+ ((MainWindow)Application.Current.MainWindow).ClearHistory();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Pages/OrderPage.xaml b/ChudoObuv/Pages/OrderPage.xaml
new file mode 100644
index 0000000..69b6f7b
--- /dev/null
+++ b/ChudoObuv/Pages/OrderPage.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Pages/OrderPage.xaml.cs b/ChudoObuv/Pages/OrderPage.xaml.cs
new file mode 100644
index 0000000..8e44e6b
--- /dev/null
+++ b/ChudoObuv/Pages/OrderPage.xaml.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Globalization;
+using ChudoObuv.Data;
+using ChudoObuv.Logic;
+using ChudoObuv.Models;
+namespace ChudoObuv.Pages
+{
+ public partial class OrderPage : Page
+ {
+ private readonly Order order;
+ private List items = new List();
+ public OrderPage(Order order)
+ {
+ InitializeComponent();
+ this.order = order;
+ Title = $"Состав заказа No {order.Id}";
+ }
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ bool isAdmin = Session.CurrentUser.IsAdmin;
+ OrderDateText.Visibility = isAdmin ? Visibility.Collapsed : Visibility.Visible;
+ OrderDatePicker.Visibility = isAdmin ? Visibility.Visible : Visibility.Collapsed;
+ SaveDateButton.Visibility = isAdmin ? Visibility.Visible : Visibility.Collapsed;
+ DeleteColumn.Visibility = isAdmin ? Visibility.Visible : Visibility.Collapsed;
+ HeaderText.Text = $"Заказ No {order.Id}. Клиент: {order.ClientFullName}";
+ OrderDateText.Text = order.OrderDate.ToString("dd.MM.yyyy");
+ OrderDatePicker.SelectedDate = order.OrderDate;
+ LoadItems();
+ }
+ private void LoadItems()
+ {
+ try
+ {
+ items = DataService.GetOrderItems(order.Id);
+
+}
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ items = new List();
+ }
+ ItemsDataGrid.ItemsSource = items;
+ TotalText.Text = $"Итоговая сумма по заказу: {items.Sum(item => item.Sum):N2} ₽";
+ }
+ private void SaveDateButton_Click(object sender, RoutedEventArgs e)
+ {
+ // Дату, введенную с клавиатуры, разбираем сами: DatePicker применяет ее только при потере фокуса
+ if (!DateTime.TryParseExact(OrderDatePicker.Text.Trim(), "dd.MM.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime newDate))
+ {
+ Messages.ShowWarning("Дата заказа указана неверно. Выберите ее в календаре или введите в формате ДД.ММ.ГГГГ, например 15.04.2026.");
+ OrderDatePicker.Focus();
+ return;
+ }
+ if (newDate.Date > DateTime.Today)
+ {
+ Messages.ShowWarning("Дата заказа не может быть позже сегодняшней. Выберите другую дату.");
+ return;
+ }
+ try
+ {
+ DataService.UpdateOrderDate(order.Id, newDate);
+ order.OrderDate = newDate;
+ Messages.ShowInfo($"Дата заказа No {order.Id} изменена на {newDate:dd.MM.yyyy}.");
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ }
+ }
+ private void DeleteItemButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (((Button)sender).DataContext is not OrderItem item)
+ {
+ return;
+ }
+ if (items.Count == 1)
+ {
+ Messages.ShowWarning("Это последняя позиция заказа. Пустой заказ хранить нельзя — удалите весь заказ на странице «Список заказов».");
+ return;
+ }
+ if (!Messages.Confirm($"Удалить позицию «{item.Position}» из заказа No {order.Id}?\nТовар вернется на склад.Действие нельзя отменить."))
+ {
+ return;
+ }
+ try
+ {
+ DataService.DeleteOrderItem(item.Id);
+ LoadItems();
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Pages/OrdersPage.xaml b/ChudoObuv/Pages/OrdersPage.xaml
new file mode 100644
index 0000000..a8d7375
--- /dev/null
+++ b/ChudoObuv/Pages/OrdersPage.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Pages/OrdersPage.xaml.cs b/ChudoObuv/Pages/OrdersPage.xaml.cs
new file mode 100644
index 0000000..57807cf
--- /dev/null
+++ b/ChudoObuv/Pages/OrdersPage.xaml.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ChudoObuv.Data;
+using ChudoObuv.Logic;
+using ChudoObuv.Models;
+namespace ChudoObuv.Pages
+{
+ public partial class OrdersPage : Page
+ {
+ public OrdersPage()
+ {
+ InitializeComponent();
+
+
+}
+ // Список перечитывается при каждом открытии страницы (после добавления, изменения, удаления)
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ if (ClientComboBox.ItemsSource == null)
+ {
+ ClientComboBox.ItemsSource = DataService.GetClients();
+ }
+ OrdersDataGrid.ItemsSource = DataService.GetOrders();
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ }
+ }
+ private Order GetSelectedOrder()
+ {
+ if (OrdersDataGrid.SelectedItem is Order order)
+ {
+ return order;
+ }
+ Messages.ShowWarning("Сначала выберите заказ в списке (щелкните по строке).");
+ return null;
+ }
+ private void AddOrderButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (ClientComboBox.SelectedItem is not User client)
+ {
+ Messages.ShowWarning("Выберите клиента, для которого оформляется заказ.");
+ ClientComboBox.Focus();
+ return;
+ }
+ if (Session.Cart.Count > 0 && !Messages.Confirm("Ранее начатый неподтвержденный заказ будет отменен.Продолжить ? "))
+ {
+ return;
+ }
+ Session.StartOrderFor(client);
+ NavigationService.Navigate(new CatalogPage());
+ }
+ private void CatalogButton_Click(object sender, RoutedEventArgs e)
+ {
+ NavigationService.Navigate(new CatalogPage());
+ }
+ private void OpenOrderButton_Click(object sender, RoutedEventArgs e)
+ {
+ Order order = GetSelectedOrder();
+ if (order != null)
+ {
+ NavigationService.Navigate(new OrderPage(order));
+ }
+ }
+ private void OrdersDataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+ {
+ if (OrdersDataGrid.SelectedItem is Order order)
+ {
+ NavigationService.Navigate(new OrderPage(order));
+ }
+ }
+ private void DeleteOrderButton_Click(object sender, RoutedEventArgs e)
+ {
+ Order order = GetSelectedOrder();
+ if (order == null)
+ {
+ return;
+ }
+
+if (!Messages.Confirm($"Удалить заказ No {order.Id} от {order.OrderDate:dd.MM.yyyy} ({ order.ClientFullName})?\n" + "Товары вернутся на склад. Действие нельзя отменить."))
+ {
+ return;
+ }
+ try
+ {
+ DataService.DeleteOrder(order.Id);
+ OrdersDataGrid.ItemsSource = DataService.GetOrders();
+ Messages.ShowInfo($"Заказ No {order.Id} удален.");
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Pages/ProductPage.xaml b/ChudoObuv/Pages/ProductPage.xaml
new file mode 100644
index 0000000..a9adc4c
--- /dev/null
+++ b/ChudoObuv/Pages/ProductPage.xaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ChudoObuv/Pages/ProductPage.xaml.cs b/ChudoObuv/Pages/ProductPage.xaml.cs
new file mode 100644
index 0000000..31717b0
--- /dev/null
+++ b/ChudoObuv/Pages/ProductPage.xaml.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ChudoObuv.Data;
+using ChudoObuv.Logic;
+using ChudoObuv.Models;
+namespace ChudoObuv.Pages
+{
+ public partial class ProductPage : Page
+ {
+ private readonly Product product;
+ private List stockItems = new List();
+ public ProductPage(Product product)
+ {
+ InitializeComponent();
+ this.product = product;
+ Title = $"Просмотр товара: {product.Name}";
+ }
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ ProductImage.Source = new BitmapImage(new Uri(product.ImagePath));
+ NameText.Text = product.Name;
+ ManufacturerRun.Text = product.Manufacturer;
+ CategoryRun.Text = $"{product.Category} / {product.Subcategory}";
+ DiscountedPriceText.Text = $"{product.DiscountedPrice:N2} ₽";
+ OldPriceText.Text = product.HasDiscount ? $"{product.Price:N2} ₽" : "";
+ CompositionRun.Text = product.Composition;
+ DescriptionRun.Text = product.Description;
+ LoadSizes();
+ }
+ ///
+ /// Загружает актуальные остатки из БД и учитывает то, что уже добавлено в заказ.
+ ///
+ private void LoadSizes()
+ {
+ try
+ {
+ stockItems = DataService.GetStockItems(product.Id);
+ }
+ catch (Exception ex)
+ {
+ Messages.ShowDatabaseError(ex);
+ stockItems = new List();
+ }
+ SizeRangeRun.Text = stockItems.Count > 0 ? string.Join(", ", stockItems.Select(item =>
+ item.SizeText)) : "нет данных";
+ List available = stockItems
+ .Where(item => item.Quantity - Session.GetQuantityInCart(item.Id) > 0)
+ .ToList();
+ AvailableSizesRun.Text = available.Count > 0 ? string.Join(", ", available.Select(item =>
+ item.SizeText)) : "нет в наличии";
+ SizeComboBox.ItemsSource = available;
+ SizeComboBox.SelectedIndex = available.Count > 0 ? 0 : -1;
+ UpdateAvailableText();
+ }
+ private int GetAvailableQuantity(StockItem stockItem)
+ {
+ return stockItem.Quantity - Session.GetQuantityInCart(stockItem.Id);
+ }
+ private void SizeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+
+{
+UpdateAvailableText();
+}
+private void UpdateAvailableText()
+ {
+ AvailableText.Text = SizeComboBox.SelectedItem is StockItem stockItem
+ ? $"доступно: {GetAvailableQuantity(stockItem)} пар"
+ : "";
+ }
+ // В поле количества можно вводить только цифры
+ private void QuantityTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
+ {
+ e.Handled = !e.Text.All(char.IsDigit);
+ }
+ private void AddButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (SizeComboBox.SelectedItem is not StockItem stockItem)
+ {
+ Messages.ShowWarning("Выберите размер обуви. Если список размеров пуст — товара нет в наличии.");
+ return;
+ }
+ int available = GetAvailableQuantity(stockItem);
+ if (!int.TryParse(QuantityTextBox.Text, out int quantity) || quantity <= 0)
+ {
+ Messages.ShowWarning("Количество указано неверно. Введите целое число пар больше нуля.");
+ QuantityTextBox.Focus();
+ return;
+ }
+ if (quantity > available)
+ {
+ Messages.ShowWarning($"Для размера {stockItem.SizeText} доступно только {available} пар. Уменьшите количество.");
+ QuantityTextBox.Focus();
+ return;
+ }
+ Session.AddToCart(new OrderItem
+ {
+ StockItemId = stockItem.Id,
+ ProductName = product.Name,
+ Manufacturer = product.Manufacturer,
+ Size = stockItem.Size,
+ Quantity = quantity,
+ UnitPrice = product.DiscountedPrice
+ });
+ Messages.ShowInfo($"Товар «{product.Name}», размер {stockItem.SizeText}, {quantity} пар добавлен в заказ.\n" +
+ "Добавьте другие товары или перейдите к оформлению заказа.");
+ QuantityTextBox.Text = "1";
+ LoadSizes();
+ }
+ private void CartButton_Click(object sender, RoutedEventArgs e)
+ {
+ NavigationService.Navigate(new CartPage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Resources/Images/IMG_KB_164811.png b/ChudoObuv/Resources/Images/IMG_KB_164811.png
new file mode 100644
index 0000000..a1e5ac3
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KB_164811.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KB_164816.png b/ChudoObuv/Resources/Images/IMG_KB_164816.png
new file mode 100644
index 0000000..c5c871e
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KB_164816.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KB_185501.png b/ChudoObuv/Resources/Images/IMG_KB_185501.png
new file mode 100644
index 0000000..810da5d
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KB_185501.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KS_195213.png b/ChudoObuv/Resources/Images/IMG_KS_195213.png
new file mode 100644
index 0000000..8ac425d
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KS_195213.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KS_195217.png b/ChudoObuv/Resources/Images/IMG_KS_195217.png
new file mode 100644
index 0000000..43004a3
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KS_195217.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KS_195222.png b/ChudoObuv/Resources/Images/IMG_KS_195222.png
new file mode 100644
index 0000000..6381af7
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KS_195222.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KSd_185508.png b/ChudoObuv/Resources/Images/IMG_KSd_185508.png
new file mode 100644
index 0000000..53352c8
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KSd_185508.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KSd_195207.png b/ChudoObuv/Resources/Images/IMG_KSd_195207.png
new file mode 100644
index 0000000..9708d12
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KSd_195207.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_KSho_185512.png b/ChudoObuv/Resources/Images/IMG_KSho_185512.png
new file mode 100644
index 0000000..997cd08
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_KSho_185512.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MB_174349.png b/ChudoObuv/Resources/Images/IMG_MB_174349.png
new file mode 100644
index 0000000..fc0365e
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MB_174349.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MB_191200.png b/ChudoObuv/Resources/Images/IMG_MB_191200.png
new file mode 100644
index 0000000..d142ead
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MB_191200.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MB_191205.png b/ChudoObuv/Resources/Images/IMG_MB_191205.png
new file mode 100644
index 0000000..39ae958
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MB_191205.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MS_185531.png b/ChudoObuv/Resources/Images/IMG_MS_185531.png
new file mode 100644
index 0000000..fe4893e
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MS_185531.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MS_185532.png b/ChudoObuv/Resources/Images/IMG_MS_185532.png
new file mode 100644
index 0000000..b782659
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MS_185532.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MS_185533.png b/ChudoObuv/Resources/Images/IMG_MS_185533.png
new file mode 100644
index 0000000..1c1e975
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MS_185533.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MSho_190514.png b/ChudoObuv/Resources/Images/IMG_MSho_190514.png
new file mode 100644
index 0000000..985e243
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MSho_190514.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MSho_190518.png b/ChudoObuv/Resources/Images/IMG_MSho_190518.png
new file mode 100644
index 0000000..804e54c
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MSho_190518.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_MSho_191612.png b/ChudoObuv/Resources/Images/IMG_MSho_191612.png
new file mode 100644
index 0000000..acd5f89
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_MSho_191612.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WB_170859.png b/ChudoObuv/Resources/Images/IMG_WB_170859.png
new file mode 100644
index 0000000..026528c
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WB_170859.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WB_170905.png b/ChudoObuv/Resources/Images/IMG_WB_170905.png
new file mode 100644
index 0000000..d243a1f
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WB_170905.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WB_170906.png b/ChudoObuv/Resources/Images/IMG_WB_170906.png
new file mode 100644
index 0000000..c9f9974
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WB_170906.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WS_174110.png b/ChudoObuv/Resources/Images/IMG_WS_174110.png
new file mode 100644
index 0000000..5831737
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WS_174110.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WS_185528.png b/ChudoObuv/Resources/Images/IMG_WS_185528.png
new file mode 100644
index 0000000..1ef1e54
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WS_185528.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WS_185535.png b/ChudoObuv/Resources/Images/IMG_WS_185535.png
new file mode 100644
index 0000000..17f99ea
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WS_185535.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WS_185538.png b/ChudoObuv/Resources/Images/IMG_WS_185538.png
new file mode 100644
index 0000000..7e3ef00
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WS_185538.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WSd_174332.png b/ChudoObuv/Resources/Images/IMG_WSd_174332.png
new file mode 100644
index 0000000..187ced6
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WSd_174332.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WSd_185156.png b/ChudoObuv/Resources/Images/IMG_WSd_185156.png
new file mode 100644
index 0000000..f189ba5
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WSd_185156.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WSd_185551.png b/ChudoObuv/Resources/Images/IMG_WSd_185551.png
new file mode 100644
index 0000000..7619074
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WSd_185551.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WSho_174409.png b/ChudoObuv/Resources/Images/IMG_WSho_174409.png
new file mode 100644
index 0000000..85e4278
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WSho_174409.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WSho_185202.png b/ChudoObuv/Resources/Images/IMG_WSho_185202.png
new file mode 100644
index 0000000..1e553c9
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WSho_185202.png differ
diff --git a/ChudoObuv/Resources/Images/IMG_WSho_185545.png b/ChudoObuv/Resources/Images/IMG_WSho_185545.png
new file mode 100644
index 0000000..fa54cca
Binary files /dev/null and b/ChudoObuv/Resources/Images/IMG_WSho_185545.png differ
diff --git a/ChudoObuv/Resources/app.ico b/ChudoObuv/Resources/app.ico
new file mode 100644
index 0000000..d1657ab
Binary files /dev/null and b/ChudoObuv/Resources/app.ico differ
diff --git a/ChudoObuv/Resources/logo.png b/ChudoObuv/Resources/logo.png
new file mode 100644
index 0000000..6665d36
Binary files /dev/null and b/ChudoObuv/Resources/logo.png differ
diff --git a/ChudoObuv/Resources/picture.png b/ChudoObuv/Resources/picture.png
new file mode 100644
index 0000000..819e334
Binary files /dev/null and b/ChudoObuv/Resources/picture.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.deps.json b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.deps.json
new file mode 100644
index 0000000..6c00042
--- /dev/null
+++ b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.deps.json
@@ -0,0 +1,78 @@
+{
+ "runtimeTarget": {
+ "name": ".NETCoreApp,Version=v8.0",
+ "signature": ""
+ },
+ "compilationOptions": {},
+ "targets": {
+ ".NETCoreApp,Version=v8.0": {
+ "ChudoObuv/1.0.0": {
+ "dependencies": {
+ "MySqlConnector": "2.6.2"
+ },
+ "runtime": {
+ "ChudoObuv.dll": {}
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
+ "runtime": {
+ "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
+ "assemblyVersion": "8.0.0.0",
+ "fileVersion": "8.0.1024.46610"
+ }
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions/8.0.2": {
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ },
+ "runtime": {
+ "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
+ "assemblyVersion": "8.0.0.0",
+ "fileVersion": "8.0.1024.46610"
+ }
+ }
+ },
+ "MySqlConnector/2.6.2": {
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
+ },
+ "runtime": {
+ "lib/net8.0/MySqlConnector.dll": {
+ "assemblyVersion": "2.0.0.0",
+ "fileVersion": "2.6.2.0"
+ }
+ }
+ }
+ }
+ },
+ "libraries": {
+ "ChudoObuv/1.0.0": {
+ "type": "project",
+ "serviceable": false,
+ "sha512": ""
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==",
+ "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2",
+ "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512"
+ },
+ "Microsoft.Extensions.Logging.Abstractions/8.0.2": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-nroMDjS7hNBPtkZqVBbSiQaQjWRDxITI8Y7XnDs97rqG3EbzVTNLZQf7bIeUJcaHOV8bca47s1Uxq94+2oGdxA==",
+ "path": "microsoft.extensions.logging.abstractions/8.0.2",
+ "hashPath": "microsoft.extensions.logging.abstractions.8.0.2.nupkg.sha512"
+ },
+ "MySqlConnector/2.6.2": {
+ "type": "package",
+ "serviceable": true,
+ "sha512": "sha512-dlTc/tsBa42szdvpj4nrHvQVUb0gsMwR9HT6J0Zz2OSqfP0CdYlGw+qQPqCpbnO97idfvclSjKYtM6y5QaBQaQ==",
+ "path": "mysqlconnector/2.6.2",
+ "hashPath": "mysqlconnector.2.6.2.nupkg.sha512"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.dll b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.dll
new file mode 100644
index 0000000..1f1e62b
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.dll differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.exe b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.exe
new file mode 100644
index 0000000..9894dbd
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.exe differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.runtimeconfig.json b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.runtimeconfig.json
new file mode 100644
index 0000000..b65a073
--- /dev/null
+++ b/ChudoObuv/Исполняемые_файлы/net8.0-windows/ChudoObuv.runtimeconfig.json
@@ -0,0 +1,19 @@
+{
+ "runtimeOptions": {
+ "tfm": "net8.0",
+ "frameworks": [
+ {
+ "name": "Microsoft.NETCore.App",
+ "version": "8.0.0"
+ },
+ {
+ "name": "Microsoft.WindowsDesktop.App",
+ "version": "8.0.0"
+ }
+ ],
+ "configProperties": {
+ "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
+ "CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Microsoft.Extensions.DependencyInjection.Abstractions.dll
new file mode 100644
index 0000000..81ed3de
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Microsoft.Extensions.Logging.Abstractions.dll b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Microsoft.Extensions.Logging.Abstractions.dll
new file mode 100644
index 0000000..f9d1dc6
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Microsoft.Extensions.Logging.Abstractions.dll differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/MySqlConnector.dll b/ChudoObuv/Исполняемые_файлы/net8.0-windows/MySqlConnector.dll
new file mode 100644
index 0000000..2b1d815
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/MySqlConnector.dll differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_164811.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_164811.png
new file mode 100644
index 0000000..a1e5ac3
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_164811.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_164816.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_164816.png
new file mode 100644
index 0000000..c5c871e
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_164816.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_185501.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_185501.png
new file mode 100644
index 0000000..810da5d
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KB_185501.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195213.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195213.png
new file mode 100644
index 0000000..8ac425d
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195213.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195217.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195217.png
new file mode 100644
index 0000000..43004a3
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195217.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195222.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195222.png
new file mode 100644
index 0000000..6381af7
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KS_195222.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSd_185508.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSd_185508.png
new file mode 100644
index 0000000..53352c8
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSd_185508.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSd_195207.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSd_195207.png
new file mode 100644
index 0000000..9708d12
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSd_195207.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSho_185512.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSho_185512.png
new file mode 100644
index 0000000..997cd08
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_KSho_185512.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_174349.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_174349.png
new file mode 100644
index 0000000..fc0365e
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_174349.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_191200.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_191200.png
new file mode 100644
index 0000000..d142ead
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_191200.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_191205.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_191205.png
new file mode 100644
index 0000000..39ae958
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MB_191205.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185531.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185531.png
new file mode 100644
index 0000000..fe4893e
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185531.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185532.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185532.png
new file mode 100644
index 0000000..b782659
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185532.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185533.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185533.png
new file mode 100644
index 0000000..1c1e975
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MS_185533.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_190514.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_190514.png
new file mode 100644
index 0000000..985e243
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_190514.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_190518.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_190518.png
new file mode 100644
index 0000000..804e54c
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_190518.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_191612.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_191612.png
new file mode 100644
index 0000000..acd5f89
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_MSho_191612.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170859.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170859.png
new file mode 100644
index 0000000..026528c
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170859.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170905.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170905.png
new file mode 100644
index 0000000..d243a1f
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170905.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170906.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170906.png
new file mode 100644
index 0000000..c9f9974
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WB_170906.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_174110.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_174110.png
new file mode 100644
index 0000000..5831737
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_174110.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185528.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185528.png
new file mode 100644
index 0000000..1ef1e54
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185528.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185535.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185535.png
new file mode 100644
index 0000000..17f99ea
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185535.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185538.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185538.png
new file mode 100644
index 0000000..7e3ef00
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WS_185538.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_174332.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_174332.png
new file mode 100644
index 0000000..187ced6
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_174332.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_185156.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_185156.png
new file mode 100644
index 0000000..f189ba5
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_185156.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_185551.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_185551.png
new file mode 100644
index 0000000..7619074
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSd_185551.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_174409.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_174409.png
new file mode 100644
index 0000000..85e4278
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_174409.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_185202.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_185202.png
new file mode 100644
index 0000000..1e553c9
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_185202.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_185545.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_185545.png
new file mode 100644
index 0000000..fa54cca
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/Images/IMG_WSho_185545.png differ
diff --git a/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/picture.png b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/picture.png
new file mode 100644
index 0000000..819e334
Binary files /dev/null and b/ChudoObuv/Исполняемые_файлы/net8.0-windows/Resources/picture.png differ