169 lines
5.0 KiB
Python
169 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
from __future__ import annotations
|
||
|
||
from collections import defaultdict
|
||
from pathlib import Path
|
||
|
||
|
||
Order = dict[str, str | int | float]
|
||
|
||
|
||
def load_orders(filepath: str) -> list[Order]:
|
||
orders: list[Order] = []
|
||
|
||
with open(filepath, "r", encoding="utf-8") as file:
|
||
for line_number, raw_line in enumerate(file, start=1):
|
||
line = raw_line.strip()
|
||
if not line:
|
||
continue
|
||
|
||
parts = [part.strip() for part in line.split(",")]
|
||
if len(parts) != 4:
|
||
raise ValueError(
|
||
f"Некорректный формат строки {line_number}: ожидалось 4 поля."
|
||
)
|
||
|
||
customer, drink, quantity_text, price_text = parts
|
||
|
||
try:
|
||
quantity = int(quantity_text)
|
||
price = float(price_text)
|
||
except ValueError as error:
|
||
raise ValueError(
|
||
f"Ошибка в числовых данных строки {line_number}: {line}"
|
||
) from error
|
||
|
||
orders.append(
|
||
{
|
||
"customer": customer,
|
||
"drink": drink.title(),
|
||
"quantity": quantity,
|
||
"price": price,
|
||
}
|
||
)
|
||
|
||
return orders
|
||
|
||
|
||
def normalize_names(orders: list[Order]) -> list[Order]:
|
||
normalized_orders: list[Order] = []
|
||
|
||
for order in orders:
|
||
normalized_order = order.copy()
|
||
customer = str(normalized_order["customer"]).strip()
|
||
normalized_order["customer"] = customer.capitalize()
|
||
normalized_orders.append(normalized_order)
|
||
|
||
return normalized_orders
|
||
|
||
|
||
def filter_by_drink(orders: list[Order], drink: str) -> list[Order]:
|
||
target = drink.strip().lower()
|
||
return [
|
||
order
|
||
for order in orders
|
||
if str(order["drink"]).strip().lower() == target
|
||
]
|
||
|
||
|
||
def calculate_total(orders: list[Order]) -> float:
|
||
return sum(float(order["quantity"]) * float(order["price"]) for order in orders)
|
||
|
||
|
||
def top_clients(orders: list[Order], n: int) -> list[str]:
|
||
spent_by_client: defaultdict[str, float] = defaultdict(float)
|
||
|
||
for order in orders:
|
||
customer = str(order["customer"])
|
||
spent_by_client[customer] += float(order["quantity"]) * float(order["price"])
|
||
|
||
sorted_clients = sorted(
|
||
spent_by_client.items(),
|
||
key=lambda item: (-item[1], item[0]),
|
||
)
|
||
return [client for client, _ in sorted_clients[:n]]
|
||
|
||
|
||
def drinks_summary(orders: list[Order]) -> dict[str, int]:
|
||
summary: defaultdict[str, int] = defaultdict(int)
|
||
|
||
for order in orders:
|
||
drink = str(order["drink"]).strip().title()
|
||
summary[drink] += int(order["quantity"])
|
||
|
||
return dict(summary)
|
||
|
||
|
||
def most_popular_drink(summary: dict[str, int]) -> str:
|
||
if not summary:
|
||
return ""
|
||
return max(summary, key=summary.get)
|
||
|
||
|
||
def average_order_value(orders: list[Order]) -> float:
|
||
if not orders:
|
||
return 0.0
|
||
return round(calculate_total(orders) / len(orders), 2)
|
||
|
||
|
||
def format_report(
|
||
summary: dict[str, int], top: list[str], popular: str, total: float
|
||
) -> str:
|
||
drinks_lines = "\n".join(
|
||
f"- {drink}: {quantity}" for drink, quantity in sorted(summary.items())
|
||
)
|
||
top_clients_line = ", ".join(top) if top else "Нет данных"
|
||
|
||
return (
|
||
"===== Отчет по кофейне =====\n"
|
||
"Сводка по напиткам:\n"
|
||
f"{drinks_lines}\n"
|
||
f"Самый популярный напиток: {popular}\n"
|
||
f"Топ клиентов: {top_clients_line}\n"
|
||
f"Общая выручка: {total:.2f} руб.\n"
|
||
"============================"
|
||
)
|
||
|
||
|
||
def save_report(report: str, filepath: str) -> None:
|
||
path = Path(filepath)
|
||
path.parent.mkdir(parents=True, exist_ok=True)
|
||
path.write_text(report, encoding="utf-8-sig")
|
||
|
||
|
||
def main() -> None:
|
||
base_dir = Path(__file__).resolve().parent
|
||
data_path = base_dir / "data" / "data.txt"
|
||
report_path = base_dir / "data" / "report.txt"
|
||
|
||
orders = load_orders(str(data_path))
|
||
orders = normalize_names(orders)
|
||
|
||
summary = drinks_summary(orders)
|
||
popular_drink = most_popular_drink(summary)
|
||
|
||
popular_orders = filter_by_drink(orders, popular_drink)
|
||
print(f"Заказы по напитку '{popular_drink}':")
|
||
for order in popular_orders:
|
||
print(
|
||
f"{order['customer']} - {order['drink']} - "
|
||
f"{order['quantity']} шт. по {order['price']:.2f} руб."
|
||
)
|
||
|
||
total = calculate_total(orders)
|
||
top = top_clients(orders, 3)
|
||
|
||
average = average_order_value(orders)
|
||
print(f"\nСредняя стоимость заказа: {average:.2f} руб.")
|
||
|
||
report = format_report(summary, top, popular_drink, total)
|
||
save_report(report, str(report_path))
|
||
|
||
print("\nОтчет сформирован:")
|
||
print(report)
|
||
print(f"\nОтчет сохранен в файл: {report_path}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|