diff --git a/.idea/ALEXSim.iml b/.idea/ALEXSim.iml
index d0876a7..3428ebc 100644
--- a/.idea/ALEXSim.iml
+++ b/.idea/ALEXSim.iml
@@ -1,8 +1,10 @@
-
-
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 6966e54..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cart_processor.py b/cart_processor.py
new file mode 100644
index 0000000..ccab334
--- /dev/null
+++ b/cart_processor.py
@@ -0,0 +1,291 @@
+"""
+Модуль обработки корзины интернет-магазина
+"""
+
+import os
+from typing import List, Dict, Tuple
+
+
+def load_cart(filepath: str) -> List[Dict]:
+ """
+ Загружает корзину из файла.
+ Формат строки: название|цена|количество|категория
+ """
+ cart = []
+
+ try:
+ with open(filepath, 'r', encoding='utf-8') as file:
+ for line_num, line in enumerate(file, 1):
+ line = line.strip()
+ if not line:
+ continue
+
+ parts = line.split('|')
+ if len(parts) != 4:
+ print(f"Предупреждение: строка {line_num} имеет неверный формат, пропущена")
+ continue
+
+ try:
+ name = parts[0].strip()
+ price = float(parts[1].strip())
+ quantity = int(parts[2].strip())
+ category = parts[3].strip()
+
+ if price < 0 or quantity <= 0:
+ print(f"Предупреждение: строка {line_num} содержит недопустимые значения, пропущена")
+ continue
+
+ cart.append({
+ 'name': name,
+ 'price': price,
+ 'quantity': quantity,
+ 'category': category
+ })
+ except ValueError:
+ print(f"Предупреждение: строка {line_num} содержит нечисловые значения, пропущена")
+ continue
+ except FileNotFoundError:
+ print(f"Ошибка: файл {filepath} не найден. Создайте файл с данными.")
+ return []
+
+ return cart
+
+
+def calculate_item_total(item: Dict) -> float:
+ """Вычисляет общую стоимость одного товара (цена × количество)"""
+ return item['price'] * item['quantity']
+
+
+def apply_category_discount(cart: List[Dict], category: str, discount_percent: float) -> List[Dict]:
+ """
+ Применяет скидку к товарам указанной категории.
+ Возвращает новый список (не изменяет исходный).
+ """
+ if discount_percent < 0 or discount_percent > 100:
+ raise ValueError("Скидка должна быть в диапазоне 0-100%")
+
+ new_cart = []
+ discount_factor = 1 - discount_percent / 100
+
+ for item in cart:
+ new_item = item.copy()
+ if item['category'].lower() == category.lower():
+ new_price = item['price'] * discount_factor
+ new_item['price'] = max(0, round(new_price, 2)) # цена не может быть отрицательной
+ new_cart.append(new_item)
+
+ return new_cart
+
+
+def calculate_subtotal(cart: List[Dict]) -> float:
+ """Вычисляет общую сумму всех товаров в корзине"""
+ total = sum(calculate_item_total(item) for item in cart)
+ return round(total, 2)
+
+
+def apply_bulk_discount(subtotal: float, total_quantity: int, threshold: int, discount_percent: float) -> float:
+ """
+ Применяет скидку на общую сумму, если количество товаров превышает порог.
+ """
+ if threshold <= 0 or discount_percent < 0 or discount_percent > 100:
+ raise ValueError("Недопустимые параметры скидки")
+
+ if total_quantity >= threshold:
+ discount_amount = subtotal * (discount_percent / 100)
+ return round(subtotal - discount_amount, 2)
+ return subtotal
+
+
+def calculate_delivery_cost(subtotal: float, free_threshold: float, base_cost: float = 5.0) -> float:
+ """
+ Рассчитывает стоимость доставки.
+ Бесплатно, если сумма заказа >= порога.
+ """
+ if free_threshold < 0 or base_cost < 0:
+ raise ValueError("Стоимость не может быть отрицательной")
+
+ if subtotal >= free_threshold:
+ return 0.0
+ return base_cost
+
+
+def find_most_expensive_item(cart: List[Dict]) -> Dict:
+ """Возвращает товар с максимальной итоговой стоимостью"""
+ if not cart:
+ return {}
+
+ most_expensive = max(cart, key=calculate_item_total)
+ return most_expensive
+
+
+def group_by_category(cart: List[Dict]) -> Dict[str, List[Dict]]:
+ """Группирует товары по категориям"""
+ groups = {}
+ for item in cart:
+ category = item['category']
+ if category not in groups:
+ groups[category] = []
+ groups[category].append(item)
+ return groups
+
+
+def detect_duplicates(cart: List[Dict]) -> List[str]:
+ """Находит дубликаты товаров (по названию без учёта регистра)"""
+ name_counts = {}
+ for item in cart:
+ name_lower = item['name'].lower()
+ name_counts[name_lower] = name_counts.get(name_lower, 0) + 1
+
+ duplicates = [item['name'] for item in cart
+ if name_counts[item['name'].lower()] > 1]
+
+ # Убираем дубликаты в возвращаемом списке
+ return list(set(duplicates))
+
+
+def generate_receipt(cart: List[Dict], delivery_cost: float, final_total: float) -> str:
+ """
+ Формирует текстовый чек
+ """
+ if not cart:
+ return "Корзина пуста"
+
+ # Заголовок чека
+ receipt = []
+ receipt.append("=" * 50)
+ receipt.append("ЧЕК ПОКУПАТЕЛЯ".center(50))
+ receipt.append("=" * 50)
+ receipt.append(f"{'Товар':<20} {'Кол-во':>6} {'Цена':>10} {'Итого':>10}")
+ receipt.append("-" * 50)
+
+ # Строки товаров
+ for item in cart:
+ name = item['name'][:18] # Обрезаем длинные названия
+ quantity = item['quantity']
+ price = item['price']
+ total = calculate_item_total(item)
+
+ receipt.append(f"{name:<20} {quantity:>6} {price:>10.2f} {total:>10.2f}")
+
+ receipt.append("-" * 50)
+
+ # Информация о доставке и итоге
+ subtotal = calculate_subtotal(cart)
+ receipt.append(f"{'Подытог:':<40} {subtotal:>10.2f}")
+ receipt.append(f"{'Доставка:':<40} {delivery_cost:>10.2f}")
+ receipt.append("-" * 50)
+ receipt.append(f"{'ИТОГО К ОПЛАТЕ:':<40} {final_total:>10.2f}")
+ receipt.append("=" * 50)
+ receipt.append("Спасибо за покупку!".center(50))
+
+ return "\n".join(receipt)
+
+
+def save_to_file(content: str, filepath: str) -> None:
+ """Сохраняет содержимое в файл (создаёт директорию при необходимости)"""
+ # Создаём директорию, если её нет
+ directory = os.path.dirname(filepath)
+ if directory and not os.path.exists(directory):
+ os.makedirs(directory)
+
+ with open(filepath, 'w', encoding='utf-8') as file:
+ file.write(content)
+
+ print(f"Чек сохранён в файл: {filepath}")
+
+
+def print_cart(cart: List[Dict]) -> None:
+ """Выводит содержимое корзины в читаемом виде"""
+ print("\nСодержимое корзины:")
+ print("-" * 60)
+ for item in cart:
+ total = calculate_item_total(item)
+ print(
+ f" {item['name']:<20} | {item['price']:>8.2f} x {item['quantity']} = {total:>10.2f} | Кат: {item['category']}")
+ print("-" * 60)
+
+
+def main():
+ """Главная функция программы"""
+ print("=" * 60)
+ print("СИСТЕМА УПРАВЛЕНИЯ ЗАКАЗАМИ ИНТЕРНЕТ-МАГАЗИНА")
+ print("=" * 60)
+
+ # 1. Загрузка корзины из файла
+ cart = load_cart("data/cart.txt")
+ if not cart:
+ print("Нет данных для обработки. Программа завершена.")
+ return
+
+ # 2. Вывод содержимого корзины
+ print_cart(cart)
+
+ # 3. Расчёт начальной суммы
+ subtotal = calculate_subtotal(cart)
+ print(f"\n1. Промежуточная сумма (без скидок): {subtotal:.2f} руб.")
+
+ # 4. Применение скидки на категорию "Электроника"
+ print("\n2. Применяем скидку 15% на категорию 'Электроника'...")
+ discounted_cart = apply_category_discount(cart, "Электроника", 15)
+ subtotal_after_cat_discount = calculate_subtotal(discounted_cart)
+ print(f" Сумма после категорийной скидки: {subtotal_after_cat_discount:.2f} руб.")
+
+ # 5. Подсчёт общего количества товаров
+ total_quantity = sum(item['quantity'] for item in discounted_cart)
+ print(f"\n3. Общее количество товаров в корзине: {total_quantity} шт.")
+
+ # 6. Применение bulk-скидки (если количество >= 5)
+ subtotal_after_bulk = subtotal_after_cat_discount
+ if total_quantity >= 5:
+ subtotal_after_bulk = apply_bulk_discount(subtotal_after_cat_discount, total_quantity, 5, 10)
+ print(f" Применена bulk-скидка 10% (порог 5 шт.)")
+ print(f" Сумма после bulk-скидки: {subtotal_after_bulk:.2f} руб.")
+ else:
+ print(f" Bulk-скидка не применена (нужно {5} товаров, имеется {total_quantity})")
+
+ # 7. Расчёт стоимости доставки
+ delivery_cost = calculate_delivery_cost(subtotal_after_bulk, 2000.0, 300.0)
+ if delivery_cost == 0:
+ print(f"\n4. Доставка: БЕСПЛАТНО (сумма заказа >= 2000 руб.)")
+ else:
+ print(f"\n4. Стоимость доставки: {delivery_cost:.2f} руб.")
+
+ # 8. Поиск самого дорогого товара
+ most_expensive = find_most_expensive_item(discounted_cart)
+ if most_expensive:
+ expensive_total = calculate_item_total(most_expensive)
+ print(f"\n5. Самый дорогой товар: {most_expensive['name']} ({expensive_total:.2f} руб.)")
+
+ # 9. Группировка по категориям
+ print("\n6. Группировка товаров по категориям:")
+ grouped = group_by_category(discounted_cart)
+ for category, items in grouped.items():
+ category_total = calculate_subtotal(items)
+ items_count = sum(item['quantity'] for item in items)
+ print(f" • {category}: {items_count} шт., сумма {category_total:.2f} руб.")
+
+ # 10. Поиск дубликатов
+ duplicates = detect_duplicates(discounted_cart)
+ if duplicates:
+ print(f"\n7. ВНИМАНИЕ: Найдены дубликаты товаров: {', '.join(duplicates)}")
+ else:
+ print("\n7. Дубликаты товаров не обнаружены")
+
+ # 11. Формирование итоговой суммы к оплате
+ final_total = subtotal_after_bulk + delivery_cost
+
+ # 12. Генерация чека
+ receipt = generate_receipt(discounted_cart, delivery_cost, final_total)
+ print("\n" + receipt)
+
+ # 13. Сохранение чека в файл
+ save_to_file(receipt, "data/receipt.txt")
+
+ # 14. Финальное сообщение
+ print("\n" + "=" * 60)
+ print("✅ Программа успешно завершена!")
+ print("=" * 60)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/data/cart.txt b/data/cart.txt
new file mode 100644
index 0000000..89f4de5
--- /dev/null
+++ b/data/cart.txt
@@ -0,0 +1,7 @@
+Ноутбук|55000|1|Электроника
+Мышь|1200|2|Электроника
+Книга|800|3|Книги
+Чехол для телефона|900|1|Аксессуары
+Клавиатура|2500|1|Электроника
+Наушники|3500|1|Электроника
+Блокнот|150|4|Канцелярия
\ No newline at end of file