from decimal import Decimal, InvalidOperation
from pathlib import Path
def parse_price(raw: str) -> Decimal:
"""'45.50', '45,50', '450' -> Decimal"""
return Decimal(raw.strip().replace(",", "."))
def load_purchases(path: Path):
items = []
with path.open(encoding="utf-8") as f:
for line_no, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
# режем по ПОСЛЕДНЕМУ пробелу
parts = line.rsplit(" ", 1)
if len(parts) != 2:
print(f"[строка {line_no}] пропущено: {line!r}")
continue
name, price_raw = parts[0].strip(), parts[1]
try:
price = parse_price(price_raw)
except InvalidOperation:
print(f"[строка {line_no}] неверная цена: {price_raw!r}")
continue
items.append((name, price))
return items
def make_report(items, vat_rate=Decimal("0.20")) -> str:
if not items:
return "Список покупок пуст."
total = sum((p for _, p in items), Decimal("0"))
avg = total / len(items)
vat = total * vat_rate / (Decimal("1") + vat_rate) # НДС "внутри" цены
net = total - vat
lines = ["=" * 55,
f"{'Товар':<35}{'Цена, руб':>20}",
"-" * 55]
for name, price in items:
lines.append(f"{name:<35}{price:>20.2f}")
lines += ["-" * 55,
f"{'ИТОГО':<35}{total:>20.2f}",
f"{'Средняя цена товара':<35}{avg:>20.2f}",
f"{'В т.ч. НДС 20%':<35}{vat:>20.2f}",
f"{'Без НДС':<35}{net:>20.2f}",
"=" * 55]
cheapest = min(items, key=lambda x: x[1])
priciest = max(items, key=lambda x: x[1])
lines.append(f"Самый дешёвый : {cheapest[0]} — {cheapest[1]:.2f}")
lines.append(f"Самый дорогой : {priciest[0]} — {priciest[1]:.2f}")
lines.append(f"Позиций в чеке: {len(items)}")
return "\n".join(lines)
def main():
path = Path("purchases.txt")
if not path.exists():
path.write_text(
"Хлеб белый 45.50\n"
"Молоко 3.2% 89,90\n"
"Сыр Российский 450\n"
"Яблоки 120.75\n"
"Кофе растворимый 350,00\n",
encoding="utf-8",
)
print(f"Создан пример {path}")
items = load_purchases(path)
report = make_report(items)
print(report)
out = Path("report.txt")
out.write_text(report, encoding="utf-8")
print(f"\nОтчёт сохранён в {out}")
if __name__ == "__main__":
main()