|
import argparse |
|
from dataclasses import dataclass |
|
import csv |
|
from datetime import datetime, timedelta |
|
from collections import Counter |
|
import statistics |
|
from typing import List, Dict, Tuple |
|
|
|
|
|
@dataclass |
|
class Order: |
|
total_profit = 0 |
|
order_date: str |
|
ship_date: str |
|
product_name: str |
|
sales: str |
|
quantity: str |
|
discount: str |
|
profit: str |
|
__slots__ = ( |
|
'order_date', 'ship_date', 'product_name', |
|
'sales', 'quantity', 'discount', 'profit' |
|
) |
|
|
|
def __post_init__(self): |
|
self.order_date = self._date_from_string(self.order_date) |
|
self.ship_date = self._date_from_string(self.ship_date) |
|
self.sales = self._float_from_string(self.sales) |
|
self.quantity = int(self.quantity) |
|
self.discount = self._float_from_string(self.discount) |
|
self.profit = self._float_from_string(self.profit) |
|
|
|
|
|
def _date_from_string(self, date=None): |
|
if date is None: |
|
return datetime.strptime('11/26/90', '%m/%d/%y').date() |
|
new_date = datetime.strptime(date, '%m/%d/%y') |
|
return new_date.date() |
|
|
|
def _float_from_string(self, string): |
|
return float(string.replace(',', '.')) |
|
|
|
|
|
def read_file(path: str = None) -> List: |
|
if path is None: |
|
return False |
|
orders = [] |
|
with open(path, 'r') as f: |
|
reader = csv.DictReader(f, delimiter=';') |
|
for row in reader: |
|
orders.append(Order( |
|
order_date=row["Order Date"], |
|
ship_date=row["Ship Date"], |
|
product_name=row["Product Name"], |
|
sales=row["Sales"], |
|
quantity=row["Quantity"], |
|
discount=row["Discount"], |
|
profit=row["Profit"]) |
|
) |
|
Order.total_profit += float(row["Profit"].replace(',', '.')) |
|
return orders |
|
|
|
|
|
def count_totals(orders: List = None) -> Tuple: |
|
if orders is None: |
|
return False |
|
total_sales = Counter() |
|
total_quantity = Counter() |
|
total_profit = Counter() |
|
total_delivery = timedelta() |
|
all_times = [] |
|
for order in orders: |
|
total_sales[order.product_name] += order.sales |
|
total_quantity[order.product_name] += order.quantity |
|
total_profit[order.product_name] += order.profit |
|
total_delivery += (order.ship_date - order.order_date) |
|
all_times.append(int((order.ship_date - order.order_date).days)) |
|
|
|
avg_deliv = total_delivery / len(orders) |
|
stand_dev_deliv = statistics.stdev(all_times) |
|
del orders, all_times, total_delivery |
|
|
|
ordered_sales = sorted(dict(total_sales).items(), key=lambda item: item[1]) |
|
bad_sales = {ordered_sales[0][0]: ordered_sales[0][1]} |
|
good_sales = {ordered_sales[-1][0]: ordered_sales[-1][1]} |
|
del ordered_sales |
|
|
|
ordered_quantity = sorted( |
|
dict(total_quantity).items(), key=lambda item: item[1]) |
|
bad_quantity = {ordered_quantity[0][0]: ordered_quantity[0][1]} |
|
good_quantity = {ordered_quantity[-1][0]: ordered_quantity[-1][1]} |
|
del ordered_quantity |
|
|
|
ordered_profit = sorted(dict(total_profit).items(), |
|
key=lambda item: item[1]) |
|
bad_profit = {ordered_profit[0][0]: ordered_profit[0][1]} |
|
good_profit = {ordered_profit[-1][0]: ordered_profit[-1][1]} |
|
del ordered_profit |
|
|
|
return ( |
|
good_sales, good_quantity, good_profit, bad_sales, |
|
bad_quantity, bad_profit, avg_deliv, timedelta(stand_dev_deliv), |
|
total_sales, total_quantity, total_profit |
|
) |
|
|
|
|
|
def count_obj( |
|
total_sales: Dict = None, |
|
total_quantity: Dict = None, |
|
total_profit: Dict = None |
|
) -> List: |
|
if None in (total_sales, total_quantity, total_profit): |
|
return False |
|
result = [] |
|
for product, sales in total_sales.items(): |
|
result.append( |
|
{ |
|
'name': product, |
|
'total_sales': total_sales.get(product, None), |
|
'total_quantity': total_quantity.get(product, None), |
|
'total_profit': total_profit.get(product, None) |
|
} |
|
) |
|
return result |
|
|
|
|
|
def write_csv(data: List): |
|
fieldnames = ['name', 'total_sales', 'total_quantity', 'total_profit'] |
|
with open('result.csv', 'w') as f: |
|
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=";") |
|
writer.writeheader() |
|
writer.writerows(data) |
|
|
|
|
|
if __name__ == '__main__': |
|
parser = argparse.ArgumentParser() |
|
parser.add_argument( |
|
'--path', nargs='?', default='Orders.csv', help='Путь к CSV-файлу.' |
|
) |
|
args = parser.parse_args() |
|
try: |
|
list_orders = read_file(args.path) |
|
except: |
|
print('Произошла ошибка. Укажите аргументом "--path" путь к файлу ' |
|
'или, если программа лежит в папке с CSV-файлом, хотя бы имя ' |
|
'файла(с расширением).') |
|
exit() |
|
|
|
if list_orders: |
|
(good_sales, good_quantity, good_profit, bad_sales, bad_quantity, |
|
bad_profit, avg_deliv, stand_dev_deliv, total_sales, total_quantity, |
|
total_profit) = count_totals(list_orders) |
|
|
|
if (total_sales, total_quantity, total_profit): |
|
data = count_obj( |
|
dict(total_sales), |
|
dict(total_quantity), |
|
dict(total_profit) |
|
) |
|
|
|
if data: |
|
write_csv(data) |
|
else: |
|
raise ('Что-то пошло не так') |
|
|
|
print(f"Общий профит: \t\t\t\t\t\t {Order.total_profit}") |
|
print( |
|
f"Лучшие продукты по продажам: \t\t\t\t " |
|
f"{''.join((good_sales.keys()))}", |
|
end='' |
|
) |
|
print(f"({list((good_sales.values()))[0]})") |
|
print( |
|
f"Лучшие продукты по количеству продаж: \t\t\t " |
|
f"{''.join((good_quantity.keys()))}", |
|
end='' |
|
) |
|
print(f"({list((good_quantity.values()))[0]} шт)") |
|
print( |
|
f"Лучшие продукты по профиту: \t\t\t\t " |
|
f"{''.join((good_profit.keys()))}", |
|
end='' |
|
) |
|
print(f"({list((good_profit.values()))[0]})") |
|
print( |
|
f"Худшие продукты по продажам: \t\t\t\t " |
|
f"{''.join((bad_sales.keys()))}", |
|
end='' |
|
) |
|
print(f"({list((bad_sales.values()))[0]})") |
|
print( |
|
f"Худшие продукты по количеству продаж: \t\t\t " |
|
f"{''.join((bad_quantity.keys()))}", |
|
end='' |
|
) |
|
print(f"({list((bad_quantity.values()))[0]} шт)") |
|
print( |
|
f"Худшие продукты по профиту: \t\t\t\t " |
|
f"{''.join((bad_profit.keys()))}", |
|
end='' |
|
) |
|
print(f"({list((good_quantity.values()))[0]})") |
|
print(f"Средний срок доставки: \t\t\t\t\t {avg_deliv}") |
|
print( |
|
f"Стандартное отклонение от среднего срока доставки: \t " |
|
f"{stand_dev_deliv}" |
|
) |