Compare commits
14
Commits
a85e343869
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77e1d4d3aa | ||
|
|
838ea8d143 | ||
|
|
9d6f97e490 | ||
|
|
422c9b74f7 | ||
|
|
abecc37deb | ||
|
|
794284aa29 | ||
|
|
fab181ddbe | ||
|
|
cf16f9915a | ||
|
|
94d132aa97 | ||
|
|
3b7d5d6f6e | ||
|
|
40786b2517 | ||
|
|
e68ebc4130 | ||
|
|
0cf7622346 | ||
|
|
4a318c94f3 |
@@ -0,0 +1,9 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.log
|
||||||
|
data/
|
||||||
|
report.txt
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.tmp
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# \# Система анализа заказов интернет-магазина
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
# \## Описание
|
||||||
|
|
||||||
|
# Модуль для обработки заказов: валидация, группировка по пользователям, расчёт сумм, скидки, фильтрация, отчёты.
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
# \## Функции
|
||||||
|
|
||||||
|
# \- load\_orders – загрузка из файла
|
||||||
|
|
||||||
|
# \- validate\_orders – отбрасывание некорректных записей
|
||||||
|
|
||||||
|
# \- group\_by\_user – группировка по пользователям
|
||||||
|
|
||||||
|
# \- calculate\_user\_total – сумма трат пользователя
|
||||||
|
|
||||||
|
# \- find\_most\_expensive\_item – самый дорогой товар (за единицу)
|
||||||
|
|
||||||
|
# \- apply\_discount – применение скидки
|
||||||
|
|
||||||
|
# \- filter\_by\_price\_threshold – фильтрация по цене
|
||||||
|
|
||||||
|
# \- get\_unique\_items – уникальные названия товаров
|
||||||
|
|
||||||
|
# \- generate\_report – формирование отчёта
|
||||||
|
|
||||||
|
# \- save\_report – сохранение отчёта
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
# \## Запуск
|
||||||
|
|
||||||
|
# python order\_processor.py
|
||||||
|
|
||||||
+257
@@ -1 +1,258 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# 1. Загрузка заказов из файла
|
||||||
|
def load_orders(filepath: str) -> list[dict]:
|
||||||
|
orders = []
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as file:
|
||||||
|
for line in file:
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
parts = line.split(',')
|
||||||
|
if len(parts) != 4:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
user_id = int(parts[0].strip())
|
||||||
|
item_name = parts[1].strip()
|
||||||
|
quantity = int(parts[2].strip())
|
||||||
|
price = float(parts[3].strip())
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
total = quantity * price
|
||||||
|
orders.append({
|
||||||
|
'user_id': user_id,
|
||||||
|
'item_name': item_name,
|
||||||
|
'quantity': quantity,
|
||||||
|
'price': price,
|
||||||
|
'total': total
|
||||||
|
})
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Ошибка: файл {filepath} не найден.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при чтении файла: {e}")
|
||||||
|
return orders
|
||||||
|
|
||||||
|
|
||||||
|
# 2. Валидация заказов (удаление некорректных)
|
||||||
|
def validate_orders(orders: list[dict]) -> list[dict]:
|
||||||
|
"""
|
||||||
|
Отбрасывает заказы с quantity <= 0, price <= 0 или пустым item_name.
|
||||||
|
"""
|
||||||
|
valid_orders = []
|
||||||
|
for order in orders:
|
||||||
|
if (order['quantity'] > 0 and
|
||||||
|
order['price'] > 0 and
|
||||||
|
order['item_name'].strip() != ''):
|
||||||
|
valid_orders.append(order)
|
||||||
|
return valid_orders
|
||||||
|
|
||||||
|
|
||||||
|
# 3. Группировка заказов по пользователям
|
||||||
|
def group_by_user(orders: list[dict]) -> dict[int, list[dict]]:
|
||||||
|
"""
|
||||||
|
Группирует заказы по user_id.
|
||||||
|
"""
|
||||||
|
grouped = {}
|
||||||
|
for order in orders:
|
||||||
|
uid = order['user_id']
|
||||||
|
if uid not in grouped:
|
||||||
|
grouped[uid] = []
|
||||||
|
grouped[uid].append(order)
|
||||||
|
return grouped
|
||||||
|
|
||||||
|
|
||||||
|
# 4. Расчет общей суммы трат пользователя
|
||||||
|
def calculate_user_total(user_orders: list[dict]) -> float:
|
||||||
|
"""
|
||||||
|
Суммирует все значения 'total' для одного пользователя.
|
||||||
|
"""
|
||||||
|
return sum(order['total'] for order in user_orders)
|
||||||
|
|
||||||
|
|
||||||
|
# 5. Поиск самого дорогого товара (по цене за единицу)
|
||||||
|
def find_most_expensive_item(orders: list[dict]) -> tuple[str, float]:
|
||||||
|
"""
|
||||||
|
Возвращает (название, цена) товара с максимальной price.
|
||||||
|
"""
|
||||||
|
if not orders:
|
||||||
|
return ('', 0.0)
|
||||||
|
most_expensive = max(orders, key=lambda x: x['price'])
|
||||||
|
return (most_expensive['item_name'], most_expensive['price'])
|
||||||
|
|
||||||
|
|
||||||
|
# 6. Применение скидки ко всем заказам (возвращает новый список)
|
||||||
|
def apply_discount(orders: list[dict], discount_percent: float) -> list[dict]:
|
||||||
|
"""
|
||||||
|
Уменьшает поле 'total' на discount_percent.
|
||||||
|
Возвращает новый список заказов, не изменяя исходный.
|
||||||
|
"""
|
||||||
|
discounted_orders = []
|
||||||
|
for order in orders:
|
||||||
|
new_order = order.copy()
|
||||||
|
new_order['total'] = order['total'] * (1 - discount_percent / 100.0)
|
||||||
|
discounted_orders.append(new_order)
|
||||||
|
return discounted_orders
|
||||||
|
|
||||||
|
|
||||||
|
# 7. Фильтрация товаров по минимальной цене за единицу
|
||||||
|
def filter_by_price_threshold(orders: list[dict], min_price: float) -> list[dict]:
|
||||||
|
"""
|
||||||
|
Возвращает заказы, у которых price >= min_price.
|
||||||
|
"""
|
||||||
|
return [order for order in orders if order['price'] >= min_price]
|
||||||
|
|
||||||
|
|
||||||
|
# 8. Получение уникальных названий товаров
|
||||||
|
def get_unique_items(orders: list[dict]) -> set[str]:
|
||||||
|
"""
|
||||||
|
Возвращает множество уникальных item_name.
|
||||||
|
"""
|
||||||
|
return {order['item_name'] for order in orders}
|
||||||
|
|
||||||
|
|
||||||
|
# 9. Генерация текстового отчета
|
||||||
|
def generate_report(stats: dict) -> str:
|
||||||
|
"""
|
||||||
|
stats ожидается с ключами:
|
||||||
|
- unique_users (int)
|
||||||
|
- total_revenue (float)
|
||||||
|
- most_expensive_item (tuple (name, price))
|
||||||
|
- unique_items (set или list)
|
||||||
|
"""
|
||||||
|
report_lines = []
|
||||||
|
report_lines.append("=" * 50)
|
||||||
|
report_lines.append("ОТЧЕТ ПО ЗАКАЗАМ ИНТЕРНЕТ-МАГАЗИНА")
|
||||||
|
report_lines.append("=" * 50)
|
||||||
|
report_lines.append(f"Всего уникальных пользователей: {stats['unique_users']}")
|
||||||
|
report_lines.append(f"Общая выручка (без скидок): {stats['total_revenue']:.2f} руб.")
|
||||||
|
|
||||||
|
item_name, item_price = stats['most_expensive_item']
|
||||||
|
report_lines.append(f"Самый дорогой товар: {item_name} (цена за ед.: {item_price:.2f} руб.)")
|
||||||
|
|
||||||
|
report_lines.append(f"Уникальных товаров в ассортименте: {len(stats['unique_items'])}")
|
||||||
|
report_lines.append("Список товаров:")
|
||||||
|
for item in sorted(stats['unique_items']):
|
||||||
|
report_lines.append(f" - {item}")
|
||||||
|
|
||||||
|
report_lines.append("=" * 50)
|
||||||
|
return "\n".join(report_lines)
|
||||||
|
|
||||||
|
|
||||||
|
# 10. Сохранение отчета в файл
|
||||||
|
def save_report(filepath: str, report_text: str) -> bool:
|
||||||
|
"""
|
||||||
|
Сохраняет отчет в файл. Возвращает True при успехе.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||||
|
with open(filepath, 'w', encoding='utf-8') as file:
|
||||||
|
file.write(report_text)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при сохранении отчета: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# ГЛАВНАЯ ФУНКЦИЯ (демонстрация работы всех 10 функций)
|
||||||
|
def main():
|
||||||
|
print("=== Система анализа заказов интернет-магазина ===\n")
|
||||||
|
|
||||||
|
data_dir = "data"
|
||||||
|
|
||||||
|
# Создаем папку, если её нет
|
||||||
|
os.makedirs(data_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Путь к файлу с данными
|
||||||
|
test_file = os.path.join(data_dir, "orders_data.txt")
|
||||||
|
|
||||||
|
# Создаем тестовый файл с данными, если его нет
|
||||||
|
if not os.path.exists(test_file):
|
||||||
|
print("Создаю тестовый файл с данными...")
|
||||||
|
sample_data = [
|
||||||
|
"101, Laptop, 1, 1200.00\n",
|
||||||
|
"102, Mouse, -2, 25.50\n", # некорректный
|
||||||
|
"101, Mouse, 1, 25.50\n",
|
||||||
|
"103, Monitor, 0, 300.00\n", # некорректный
|
||||||
|
"101, Keyboard, 1, 80.00\n",
|
||||||
|
"102, Laptop, 1, 1200.00\n",
|
||||||
|
"104, USB-C Cable, 3, 15.00\n",
|
||||||
|
"105, , 1, 10.00\n" # пустое имя товара
|
||||||
|
]
|
||||||
|
with open(test_file, 'w', encoding='utf-8') as f:
|
||||||
|
f.writelines(sample_data)
|
||||||
|
print(f"Файл создан: {test_file}\n")
|
||||||
|
|
||||||
|
# Шаг 1: Загрузка заказов
|
||||||
|
print("1. Загружаю заказы из файла...")
|
||||||
|
raw_orders = load_orders(test_file)
|
||||||
|
print(f" Загружено записей: {len(raw_orders)}")
|
||||||
|
|
||||||
|
# Шаг 2: Валидация
|
||||||
|
print("2. Валидация заказов...")
|
||||||
|
valid_orders = validate_orders(raw_orders)
|
||||||
|
invalid_count = len(raw_orders) - len(valid_orders)
|
||||||
|
print(f" Отброшено некорректных записей: {invalid_count}")
|
||||||
|
print(f" Осталось корректных заказов: {len(valid_orders)}")
|
||||||
|
|
||||||
|
if not valid_orders:
|
||||||
|
print("Нет корректных заказов для обработки. Завершение.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Шаг 3: Группировка по пользователям и расчет трат
|
||||||
|
print("\n3. Аналитика по пользователям:")
|
||||||
|
grouped = group_by_user(valid_orders)
|
||||||
|
print(f" Уникальных пользователей: {len(grouped)}")
|
||||||
|
for uid, orders_list in grouped.items():
|
||||||
|
total_spent = calculate_user_total(orders_list)
|
||||||
|
print(f" Пользователь {uid}: потратил {total_spent:.2f} руб., заказов: {len(orders_list)}")
|
||||||
|
|
||||||
|
# Шаг 4: Самый дорогой товар
|
||||||
|
most_expensive = find_most_expensive_item(valid_orders)
|
||||||
|
print(f"\n4. Самый дорогой товар (по цене за ед.): {most_expensive[0]} — {most_expensive[1]:.2f} руб.")
|
||||||
|
|
||||||
|
# Шаг 5: Уникальные товары
|
||||||
|
unique_items = get_unique_items(valid_orders)
|
||||||
|
print(f"\n5. Уникальных товаров в ассортименте: {len(unique_items)}")
|
||||||
|
print(f" {sorted(unique_items)}")
|
||||||
|
|
||||||
|
# Шаг 6: Применение скидки
|
||||||
|
print("\n6. Применение скидки 10% ко всем заказам...")
|
||||||
|
original_total = sum(order['total'] for order in valid_orders)
|
||||||
|
discounted_orders = apply_discount(valid_orders, 10.0)
|
||||||
|
discounted_total = sum(order['total'] for order in discounted_orders)
|
||||||
|
print(f" Общая сумма до скидки: {original_total:.2f} руб.")
|
||||||
|
print(f" Общая сумма после скидки: {discounted_total:.2f} руб.")
|
||||||
|
|
||||||
|
# Шаг 7: Фильтрация дорогих товаров (цена >= 100)
|
||||||
|
expensive_orders = filter_by_price_threshold(valid_orders, 100.0)
|
||||||
|
print(f"\n7. Товаров дороже 100 руб. (за ед.): {len(expensive_orders)}")
|
||||||
|
for order in expensive_orders:
|
||||||
|
print(f" - {order['item_name']}: {order['price']:.2f} руб., {order['quantity']} шт.")
|
||||||
|
|
||||||
|
# Шаг 8: Формирование отчета
|
||||||
|
stats = {
|
||||||
|
'unique_users': len(grouped),
|
||||||
|
'total_revenue': original_total,
|
||||||
|
'most_expensive_item': most_expensive,
|
||||||
|
'unique_items': unique_items
|
||||||
|
}
|
||||||
|
report_text = generate_report(stats)
|
||||||
|
|
||||||
|
# Шаг 9: Вывод отчета
|
||||||
|
print("\n" + report_text)
|
||||||
|
|
||||||
|
# Шаг 10: Сохранение отчета в файл
|
||||||
|
report_path = os.path.join(data_dir, "report.txt")
|
||||||
|
success = save_report(report_path, report_text)
|
||||||
|
if success:
|
||||||
|
print(f"\nОтчет успешно сохранен в файл: {report_path}")
|
||||||
|
else:
|
||||||
|
print("\nНе удалось сохранить отчет.")
|
||||||
|
|
||||||
|
print("\n=== Работа программы завершена ===")
|
||||||
|
|
||||||
|
|
||||||
|
# Точка входа
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user