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


import json
import random
from datetime import datetime
from typing import List, Dict, Optional


class Product:
    """Класс 'Товар'."""
    def __init__(self, name: str, price: float, year: int, quantity: int):
        self.name = name
        self.price = price
        self.year = year
        self.quantity = quantity

    def to_dict(self) -> Dict:
        """Сериализация в словарь для JSON."""
        return {
            "name": self.name,
            "price": self.price,
            "year": self.year,
            "quantity": self.quantity
        }

    @classmethod
    def from_dict(cls, data: Dict) -> 'Product':
        """Десериализация из словаря."""
        return cls(data["name"], data["price"], data["year"], data["quantity"])

    def __repr__(self) -> str:
        return f"Product({self.name}, price={self.price}, year={self.year}, qty={self.quantity})"


class Warehouse:
    """Класс 'Склад'. Хранит остатки товаров."""
    def __init__(self):
        self.products: Dict[str, Product] = {}  # ключ - название товара

    def add_product(self, product: Product) -> None:
        """Добавить или увеличить количество товара на складе."""
        if product.name in self.products:
            self.products[product.name].quantity += product.quantity
        else:
            self.products[product.name] = product

    def remove_product(self, name: str, quantity: int) -> bool:
        """
        Уменьшить количество товара на складе.
        Возвращает True, если операция успешна, иначе False.
        """
        if name not in self.products:
            return False
        if self.products[name].quantity < quantity:
            return False
        self.products[name].quantity -= quantity
        if self.products[name].quantity == 0:
            del self.products[name]
        return True

    def get_quantity(self, name: str) -> int:
        """Получить остаток товара по названию."""
        return self.products[name].quantity if name in self.products else 0

    def to_dict(self) -> Dict:
        """Сериализация склада в словарь."""
        return {name: prod.to_dict() for name, prod in self.products.items()}

    @classmethod
    def from_dict(cls, data: Dict) -> 'Warehouse':
        """Десериализация склада из словаря."""
        wh = cls()
        for name, prod_data in data.items():
            wh.products[name] = Product.from_dict(prod_data)
        return wh

    def __repr__(self) -> str:
        return f"Warehouse({list(self.products.values())})"


class Supply:
    """Класс 'Поставка'. Приход товара от поставщика."""
    def __init__(self, supplier: str, products: List[Product], date: Optional[str] = None):
        self.supplier = supplier
        self.products = products
        self.date = date or datetime.now().isoformat()

    def apply(self, warehouse: Warehouse) -> None:
        """Применить поставку к складу (пополнить остатки)."""
        for prod in self.products:
            warehouse.add_product(prod)

    def to_dict(self) -> Dict:
        return {
            "supplier": self.supplier,
            "products": [p.to_dict() for p in self.products],
            "date": self.date
        }

    @classmethod
    def from_dict(cls, data: Dict) -> 'Supply':
        products = [Product.from_dict(p) for p in data["products"]]
        return cls(data["supplier"], products, data.get("date"))

    def __repr__(self) -> str:
        return f"Supply(supplier={self.supplier}, products={self.products})"


class Request:
    """Класс 'Заявка'. Спрос от организации."""
    def __init__(self, organization: str, product_name: str, quantity: int, date: Optional[str] = None):
        self.organization = organization
        self.product_name = product_name
        self.quantity = quantity
        self.date = date or datetime.now().isoformat()
        self.fulfilled = False

    def process_request(self, warehouse: Warehouse) -> bool:
        """
        Обработать заявку: списать товар со склада, если остаток позволяет.
        Возвращает True, если заявка удовлетворена.
        """
        if warehouse.remove_product(self.product_name, self.quantity):
            self.fulfilled = True
            return True
        return False

    def to_dict(self) -> Dict:
        return {
            "organization": self.organization,
            "product_name": self.product_name,
            "quantity": self.quantity,
            "date": self.date,
            "fulfilled": self.fulfilled
        }

    @classmethod
    def from_dict(cls, data: Dict) -> 'Request':
        req = cls(data["organization"], data["product_name"], data["quantity"], data.get("date"))
        req.fulfilled = data.get("fulfilled", False)
        return req

    def __repr__(self) -> str:
        status = "выполнена" if self.fulfilled else "отклонена"
        return f"Request({self.organization}, {self.product_name} x{self.quantity}, {status})"


# ----------------------------------------------------------------------
# Функции для работы с текстовым файлом (JSON как текстовый формат)
# ----------------------------------------------------------------------

def save_products_to_file(filename: str, products: List[Product]) -> None:
    """
    Сохранить список товаров в текстовый файл (в формате JSON).
    """
    data = [p.to_dict() for p in products]
    with open(filename, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def load_products_from_file(filename: str) -> List[Product]:
    """
    Загрузить список товаров из текстового файла (JSON).
    """
    with open(filename, 'r', encoding='utf-8') as f:
        data = json.load(f)
    return [Product.from_dict(item) for item in data]


def generate_test_data(filename: str = "products.txt") -> List[Product]:
    """
    Сгенерировать тестовые данные и сохранить в файл.
    Возвращает список созданных товаров.
    """
    products = [
        Product("Ноутбук", 75000, 2023, 10),
        Product("Мышь", 1200, 2024, 50),
        Product("Клавиатура", 3500, 2023, 25),
        Product("Монитор", 22000, 2022, 8),
        Product("Системный блок", 45000, 2024, 5),
        Product("Принтер", 18000, 2023, 3),
    ]
    save_products_to_file(filename, products)
    return products


# ----------------------------------------------------------------------
# Демонстрация работы системы
# ----------------------------------------------------------------------

def demo():
    print("=" * 60)
    print("ДЕМОНСТРАЦИЯ РАБОТЫ СИСТЕМЫ 'ОПТОВАЯ БАЗА'")
    print("=" * 60)

    # 1. Генерация тестового файла и загрузка товаров
    filename = "products.txt"
    print(f"\n1. Генерируем тестовый файл '{filename}' с товарами...")
    products = generate_test_data(filename)
    print("   Созданы товары:")
    for p in products:
        print(f"     {p}")

    # 2. Создаём склад и наполняем его товарами из файла
    print(f"\n2. Загружаем товары из файла '{filename}' на склад...")
    warehouse = Warehouse()
    loaded_products = load_products_from_file(filename)
    for p in loaded_products:
        warehouse.add_product(p)
    print("   Текущее состояние склада:")
    for name, prod in warehouse.products.items():
        print(f"     {prod}")

    # 3. Поставка (приход)
    print("\n3. Создаём поставку от 'ООО Поставка-Сервис'...")
    supply_products = [
        Product("Ноутбук", 78000, 2024, 5),
        Product("SSD-накопитель", 8500, 2024, 15),
    ]
    supply = Supply("ООО Поставка-Сервис", supply_products)
    print(f"   Поставка: {supply}")
    supply.apply(warehouse)
    print("   После применения поставки, склад:")
    for name, prod in warehouse.products.items():
        print(f"     {prod}")

    # 4. Заявки и их обработка с проверкой остатков
    print("\n4. Создаём и обрабатываем заявки...")
    requests = [
        Request("ООО Ромашка", "Ноутбук", 3),
        Request("ЗАО ТехноСервис", "Принтер", 2),
        Request("ИП Иванов", "SSD-накопитель", 20),  # больше, чем есть
        Request("ООО Глобус", "Клавиатура", 10),
    ]

    for req in requests:
        print(f"\n   Заявка от {req.organization}: {req.product_name} x{req.quantity}")
        success = req.process_request(warehouse)
        if success:
            print(f"     ✅ Заявка выполнена, остаток {req.product_name}: {warehouse.get_quantity(req.product_name)}")
        else:
            print(f"     ❌ Заявка отклонена! Недостаточно товара '{req.product_name}' на складе.")

    # 5. Итоговое состояние склада
    print("\n5. Итоговое состояние склада:")
    for name, prod in warehouse.products.items():
        print(f"     {prod}")

    # 6. Сохраняем историю заявок в файл (для наглядности)
    history_file = "requests_history.json"
    with open(history_file, 'w', encoding='utf-8') as f:
        json.dump([r.to_dict() for r in requests], f, ensure_ascii=False, indent=2)
    print(f"\n   История заявок сохранена в {history_file}")


if __name__ == "__main__":
    demo()