# -*- 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()