Загрузка данных


```python
import tkinter as tk
from tkinter import ttk, messagebox
import tkinter.font as tkfont

# Цвета по заданию
COLOR_BIG_DISCOUNT = "#FFDEAD"
COLOR_OUT_OF_STOCK = "#ADD8E6"
COLOR_NORMAL = "#FFFFFF"

# Тестовые пользователи
USERS = [
    {
        "login": "guest",
        "password": "123",
        "full_name": "Гость",
        "role": "Гость"
    },
    {
        "login": "client",
        "password": "123",
        "full_name": "Иванов Иван Иванович",
        "role": "Авторизованный клиент"
    },
    {
        "login": "manager",
        "password": "123",
        "full_name": "Петров Петр Петрович",
        "role": "Менеджер"
    },
    {
        "login": "admin",
        "password": "123",
        "full_name": "Администратор",
        "role": "Администратор"
    }
]

# Демонстрационные товары
PRODUCTS = [
    {
        "category": "Бытовая техника",
        "name": "Холодильник",
        "description": "Двухкамерный холодильник",
        "manufacturer": "Samsung",
        "supplier": "ООО Техно",
        "price": 45000,
        "discount": 20,
        "unit": "шт.",
        "quantity": 5,
        "image": None
    },
    {
        "category": "Компьютеры",
        "name": "Клавиатура",
        "description": "Механическая игровая клавиатура",
        "manufacturer": "Logitech",
        "supplier": "ООО Компьютер",
        "price": 5000,
        "discount": 10,
        "unit": "шт.",
        "quantity": 12,
        "image": None
    },
    {
        "category": "Телефоны",
        "name": "Смартфон",
        "description": "Смартфон с большим экраном",
        "manufacturer": "Xiaomi",
        "supplier": "ООО Мобильный",
        "price": 25000,
        "discount": 25,
        "unit": "шт.",
        "quantity": 0,
        "image": None
    },
    {
        "category": "Аксессуары",
        "name": "Наушники",
        "description": "Беспроводные наушники",
        "manufacturer": "Sony",
        "supplier": "ООО Аудио",
        "price": 8000,
        "discount": 0,
        "unit": "шт.",
        "quantity": 7,
        "image": None
    }
]


def get_background(product):
    if product["quantity"] == 0:
        return COLOR_OUT_OF_STOCK

    if product["discount"] > 17:
        return COLOR_BIG_DISCOUNT

    return COLOR_NORMAL


class LoginWindow(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Авторизация")
        self.geometry("380x360")
        self.resizable(False, False)

        self.user = None

        self.configure(bg="#F4F4F4")

        frame = tk.Frame(
            self,
            bg="white",
            padx=30,
            pady=25,
            highlightbackground="#CCCCCC",
            highlightthickness=1
        )
        frame.pack(
            padx=25,
            pady=25,
            fill="both",
            expand=True
        )

        tk.Label(
            frame,
            text="Вход в систему",
            font=("Arial", 18, "bold"),
            bg="white"
        ).pack(pady=(0, 20))

        tk.Label(
            frame,
            text="Логин",
            font=("Arial", 10),
            bg="white"
        ).pack(anchor="w")

        self.login_entry = tk.Entry(
            frame,
            font=("Arial", 11),
            relief="solid",
            bd=1
        )
        self.login_entry.pack(fill="x", pady=(5, 12))

        tk.Label(
            frame,
            text="Пароль",
            font=("Arial", 10),
            bg="white"
        ).pack(anchor="w")

        self.password_entry = tk.Entry(
            frame,
            font=("Arial", 11),
            show="*",
            relief="solid",
            bd=1
        )
        self.password_entry.pack(fill="x", pady=(5, 18))

        tk.Button(
            frame,
            text="Войти",
            font=("Arial", 10, "bold"),
            bg="#DCDCDC",
            command=self.login
        ).pack(fill="x", ipady=4)

        tk.Button(
            frame,
            text="Войти как гость",
            font=("Arial", 10),
            bg="#EEEEEE",
            command=self.login_as_guest
        ).pack(fill="x", pady=(8, 0), ipady=3)

        self.bind("<Return>", lambda event: self.login())

        self.login_entry.focus_set()

    def login(self):
        login = self.login_entry.get().strip()
        password = self.password_entry.get()

        for user in USERS:
            if (
                user["login"] == login
                and user["password"] == password
            ):
                self.user = user.copy()
                self.destroy()
                return

        messagebox.showerror(
            "Ошибка входа",
            "Неверный логин или пароль",
            parent=self
        )

    def login_as_guest(self):
        self.user = {
            "login": "",
            "password": "",
            "full_name": "Гость",
            "role": "Гость"
        }
        self.destroy()


class ProductsWindow(tk.Tk):
    def __init__(self, user):
        super().__init__()

        self.user = user
        self.logged_out = False
        self.product_images = []

        self.title("Список товаров")
        self.geometry("1050x650")
        self.minsize(750, 450)
        self.configure(bg="#F4F4F4")

        self.create_header()
        self.create_scroll_area()
        self.show_products()

    def create_header(self):
        header = tk.Frame(
            self,
            bg="white",
            padx=15,
            pady=12
        )
        header.pack(fill="x")

        tk.Label(
            header,
            text="Список товаров",
            font=("Arial", 19, "bold"),
            bg="white"
        ).pack(side="left")

        tk.Label(
            header,
            text=f'{self.user["full_name"]} | '
                 f'{self.user["role"]}',
            font=("Arial", 10),
            bg="white"
        ).pack(side="right", padx=(10, 0))

        tk.Button(
            header,
            text="Выход",
            command=self.logout
        ).pack(side="right", padx=10)

    def create_scroll_area(self):
        container = tk.Frame(self, bg="#F4F4F4")
        container.pack(fill="both", expand=True)

        self.canvas = tk.Canvas(
            container,
            bg="#F4F4F4",
            highlightthickness=0
        )

        scrollbar = ttk.Scrollbar(
            container,
            orient="vertical",
            command=self.canvas.yview
        )

        self.list_frame = tk.Frame(
            self.canvas,
            bg="#F4F4F4"
        )

        self.window_id = self.canvas.create_window(
            (0, 0),
            window=self.list_frame,
            anchor="nw"
        )

        self.list_frame.bind(
            "<Configure>",
            lambda event: self.canvas.configure(
                scrollregion=self.canvas.bbox("all")
            )
        )

        self.canvas.bind(
            "<Configure>",
            lambda event: self.canvas.itemconfigure(
                self.window_id,
                width=event.width
            )
        )

        self.canvas.configure(
            yscrollcommand=scrollbar.set
        )

        self.canvas.pack(
            side="left",
            fill="both",
            expand=True
        )

        scrollbar.pack(
            side="right",
            fill="y"
        )

        self.canvas.bind_all(
            "<MouseWheel>",
            self.on_mousewheel
        )

    def on_mousewheel(self, event):
        if self.winfo_exists():
            self.canvas.yview_scroll(
                int(-event.delta / 120),
                "units"
            )

    def show_products(self):
        for product in PRODUCTS:
            self.create_product_card(product)

    def create_product_card(self, product):
        background = get_background(product)

        # Внешняя строка товара
        card = tk.Frame(
            self.list_frame,
            bg=background,
            highlightbackground="#333333",
            highlightthickness=1
        )

        card.pack(
            fill="x",
            padx=12,
            pady=5
        )

        card.grid_columnconfigure(1, weight=1)

        # Левая часть: изображение
        photo_frame = tk.Frame(
            card,
            bg=background,
            width=180,
            height=155
        )
        photo_frame.grid(
            row=0,
            column=0,
            sticky="nsew",
            padx=5,
            pady=5
        )
        photo_frame.grid_propagate(False)

        image_path = product.get("image")

        if image_path:
            try:
                photo = tk.PhotoImage(file=image_path)
                self.product_images.append(photo)

                image_label = tk.Label(
                    photo_frame,
                    image=photo,
                    bg=background
                )
                image_label.place(
                    relx=0.5,
                    rely=0.5,
                    anchor="center"
                )

            except (tk.TclError, OSError):
                self.show_image_placeholder(photo_frame)

        else:
            self.show_image_placeholder(photo_frame)

        # Центральная часть: описание товара
        info = tk.Frame(
            card,
            bg=background,
            padx=10,
            pady=7
        )

        info.grid(
            row=0,
            column=1,
            sticky="nsew"
        )

        tk.Label(
            info,
            text=f'{product["category"]} | '
                 f'{product["name"]}',
            font=("Arial", 12, "bold"),
            bg=background,
            anchor="w",
            justify="left",
            wraplength=550
        ).pack(fill="x", pady=(0, 5))

        details = [
            f'Описание товара: {product["description"]}',
            f'Производитель: {product["manufacturer"]}',
            f'Поставщик: {product["supplier"]}',
            f'Единица измерения: {product["unit"]}',
            f'Количество на складе: {product["quantity"]}'
        ]

        for text in details:
            tk.Label(
                info,
                text=text,
                font=("Arial", 10),
                bg=background,
                anchor="w",
                justify="left",
                wraplength=550
            ).pack(fill="x")

        # Цена с учётом скидки
        price_frame = tk.Frame(
            info,
            bg=background
        )
        price_frame.pack(
            fill="x",
            anchor="w",
            pady=(5, 0)
        )

        old_price = product["price"]
        discount = product["discount"]
        new_price = old_price * (100 - discount) / 100

        if discount > 0:
            old_font = tkfont.Font(
                family="Arial",
                size=10,
                overstrike=True
            )

            tk.Label(
                price_frame,
                text=f'{old_price:.2f} руб.',
                font=old_font,
                fg="#777777",
                bg=background
            ).pack(side="left", padx=(0, 10))

            tk.Label(
                price_frame,
                text=f'{new_price:.2f} руб.',
                font=("Arial", 10, "bold"),
                fg="black",
                bg=background
            ).pack(side="left")

        else:
            tk.Label(
                price_frame,
                text=f'Цена: {old_price:.2f} руб.',
                font=("Arial", 10),
                bg=background
            ).pack(side="left")

        # Правая часть: скидка
        discount_frame = tk.Frame(
            card,
            bg=background,
            width=110
        )

        discount_frame.grid(
            row=0,
            column=2,
            sticky="ns"
        )

        discount_frame.grid_propagate(False)

        tk.Label(
            discount_frame,
            text="Действующая\nскидка",
            font=("Arial", 9),
            bg=background,
            justify="center"
        ).pack(
            expand=True,
            pady=(15, 3)
        )

        tk.Label(
            discount_frame,
            text=f'{discount}%',
            font=("Arial", 17, "bold"),
            bg=background
        ).pack(
            expand=True,
            pady=(0, 15)
        )

    def show_image_placeholder(self, parent):
        placeholder = tk.Frame(
            parent,
            bg="white",
            highlightbackground="#AAAAAA",
            highlightthickness=1
        )
        placeholder.place(
            relx=0.5,
            rely=0.5,
            anchor="center",
            width=85,
            height=55
        )

        tk.Label(
            placeholder,
            text="Фото",
            font=("Arial", 10),
            bg="white"
        ).pack(expand=True)

    def logout(self):
        self.logged_out = True
        self.destroy()


def main():
    while True:
        login_window = LoginWindow()
        login_window.mainloop()

        if login_window.user is None:
            break

        products_window = ProductsWindow(
            login_window.user
        )
        products_window.mainloop()

        if not products_window.logged_out:
            break


if __name__ == "__main__":
    main()
```