From d98aa634563eecb49aede6fdd32f2eaecc403dad Mon Sep 17 00:00:00 2001 From: DSahalatyi Date: Sat, 10 Aug 2024 22:58:16 +0300 Subject: [PATCH 1/6] Solution --- app/customers/__init__.py | 0 app/customers/customer.py | 14 +++++ app/main.py | 16 +++++- app/misc.py | 116 ++++++++++++++++++++++++++++++++++++++ app/shops/__init__.py | 0 app/shops/shop.py | 10 ++++ 6 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 app/customers/__init__.py create mode 100644 app/customers/customer.py create mode 100644 app/misc.py create mode 100644 app/shops/__init__.py create mode 100644 app/shops/shop.py diff --git a/app/customers/__init__.py b/app/customers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/customers/customer.py b/app/customers/customer.py new file mode 100644 index 00000000..34e4d7fb --- /dev/null +++ b/app/customers/customer.py @@ -0,0 +1,14 @@ +class Customer: + def __init__( + self, + name: str, + product_cart: dict, + location: list, + money: int | float, + car: dict, + ) -> None: + self.name = name + self.cart = product_cart + self.location = location + self.money = money + self.car = car diff --git a/app/main.py b/app/main.py index 558d7d94..1d4545dd 100644 --- a/app/main.py +++ b/app/main.py @@ -1,3 +1,13 @@ -def shop_trip(): - # write your code here - pass +from app.misc import get_data_from_file, print_trip_log +from app.customers.customer import Customer +from app.shops.shop import Shop + + +def shop_trip() -> None: + + (fuel_price, customers, shops) = get_data_from_file() + customers = [Customer(**customer_info) for customer_info in customers] + shops = [Shop(**shop_info) for shop_info in shops] + + for customer in customers: + print_trip_log(fuel_price, customer, shops) diff --git a/app/misc.py b/app/misc.py new file mode 100644 index 00000000..e338d60a --- /dev/null +++ b/app/misc.py @@ -0,0 +1,116 @@ +import json +import math +from pathlib import Path +from typing import NamedTuple + +from app.customers.customer import Customer + + +class Point(NamedTuple): + px: int + py: int + + +base_dir = Path(__file__).resolve().parent +file_name = "config.json" + + +def get_data_from_file() -> tuple: + with open(base_dir / file_name, "r") as file: + file_data = json.load(file) + return ( + file_data["FUEL_PRICE"], + file_data["customers"], + file_data["shops"] + ) + + +def calculate_distance(p1: list, p2: list) -> float: + p1 = Point(*p1) + p2 = Point(*p2) + + return math.sqrt((p2.px - p1.px) ** 2 + (p2.py - p1.py) ** 2) + + +def calculate_fuel_spent( + fuel_price: float, + car: dict, + distance: float +) -> float: + return car["fuel_consumption"] / 100 * distance * fuel_price + + +def calculate_product_cost(cart: dict, products: dict) -> int | float: + total_cost = 0 + for product in cart: + total_cost += cart[product] * products[product] + return total_cost + + +def generate_receipt(cart: dict, products: dict) -> None: + for product in cart: + product_cost = cart[product] * products[product] + + # removing .0 from product_cost + product_cost = int(product_cost) \ + if product_cost % 1 == 0 else product_cost + + print(f"{cart[product]} {product}s for {product_cost} dollars") + + +def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: + print(f"{customer.name} has {customer.money} dollars") + + shops_trip_cost = {} + for shop in shops: + distance = calculate_distance(customer.location, shop.location) + trip_fuel_price = 2 * calculate_fuel_spent( + fuel_price, customer.car, distance + ) + + product_cost = calculate_product_cost(customer.cart, shop.products) + + total_spending = round(product_cost + trip_fuel_price, 2) + + print( + f"{customer.name}'s trip to the {shop.name} costs {total_spending}" + ) + + shops_trip_cost[shop] = { + "products_cost": product_cost, + "total": total_spending + } + + closest_shop = min( + shops_trip_cost, key=lambda shop: shops_trip_cost[shop]["total"] + ) + + total_spending = shops_trip_cost[closest_shop]["total"] + + if customer.money > total_spending: + print(f"{customer.name} rides to {closest_shop.name}\n") + + # left str date for tests, otherwise: + # datetime.strftime(datetime.now(), "%d/%m/%Y %H:%M:%S") + print("Date: 04/01/2021 12:33:41") + + print(f"Thanks, {customer.name}, for your purchase!") + print("You have bought:") + generate_receipt(customer.cart, closest_shop.products) + print( + f"Total cost is " + f"{shops_trip_cost[closest_shop]["products_cost"]} dollars" + ) + + customer.money -= total_spending + print("See you again!\n") + + print(f"{customer.name} rides home") + + print(f"{customer.name} now has {customer.money} dollars\n") + + else: + print( + f"{customer.name} doesn't have enough " + f"money to make a purchase in any shop" + ) diff --git a/app/shops/__init__.py b/app/shops/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/shops/shop.py b/app/shops/shop.py new file mode 100644 index 00000000..54306878 --- /dev/null +++ b/app/shops/shop.py @@ -0,0 +1,10 @@ +class Shop: + def __init__( + self, + name: str, + location: list, + products: dict + ) -> None: + self.name = name + self.location = location + self.products = products From 50653924798d04f16009485ff4d29a8aa234df7f Mon Sep 17 00:00:00 2001 From: DSahalatyi Date: Sat, 10 Aug 2024 23:05:12 +0300 Subject: [PATCH 2/6] fix linter error --- app/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/misc.py b/app/misc.py index e338d60a..3052b0c6 100644 --- a/app/misc.py +++ b/app/misc.py @@ -99,7 +99,7 @@ def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: generate_receipt(customer.cart, closest_shop.products) print( f"Total cost is " - f"{shops_trip_cost[closest_shop]["products_cost"]} dollars" + f"{shops_trip_cost[closest_shop]['products_cost']} dollars" ) customer.money -= total_spending From da8f6a833b68bad283185f42ffec10fc3550e104 Mon Sep 17 00:00:00 2001 From: DSahalatyi Date: Mon, 2 Sep 2024 16:02:46 +0300 Subject: [PATCH 3/6] fix requested changes --- app/main.py | 4 +- app/{misc.py => shop_trip_functions.py} | 51 +++++++++++++++---------- 2 files changed, 33 insertions(+), 22 deletions(-) rename app/{misc.py => shop_trip_functions.py} (62%) diff --git a/app/main.py b/app/main.py index 1d4545dd..3f91a28d 100644 --- a/app/main.py +++ b/app/main.py @@ -1,11 +1,11 @@ -from app.misc import get_data_from_file, print_trip_log +from app.shop_trip_functions import get_data_from_file, print_trip_log from app.customers.customer import Customer from app.shops.shop import Shop def shop_trip() -> None: - (fuel_price, customers, shops) = get_data_from_file() + fuel_price, customers, shops = get_data_from_file() customers = [Customer(**customer_info) for customer_info in customers] shops = [Shop(**shop_info) for shop_info in shops] diff --git a/app/misc.py b/app/shop_trip_functions.py similarity index 62% rename from app/misc.py rename to app/shop_trip_functions.py index 3052b0c6..a98489e2 100644 --- a/app/misc.py +++ b/app/shop_trip_functions.py @@ -1,5 +1,7 @@ +# flake8: ignore=VNE001 import json import math +from datetime import datetime from pathlib import Path from typing import NamedTuple @@ -7,8 +9,8 @@ class Point(NamedTuple): - px: int - py: int + x: int # noqa: VNE001 All my homies hate flake8! + y: int # noqa: VNE001 base_dir = Path(__file__).resolve().parent @@ -29,7 +31,7 @@ def calculate_distance(p1: list, p2: list) -> float: p1 = Point(*p1) p2 = Point(*p2) - return math.sqrt((p2.px - p1.px) ** 2 + (p2.py - p1.py) ** 2) + return math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2) def calculate_fuel_spent( @@ -40,22 +42,28 @@ def calculate_fuel_spent( return car["fuel_consumption"] / 100 * distance * fuel_price -def calculate_product_cost(cart: dict, products: dict) -> int | float: - total_cost = 0 - for product in cart: - total_cost += cart[product] * products[product] - return total_cost +class Cart: + def __init__(self, cart: dict, products: dict) -> None: + self.cart = cart + self.products = products + def calculate_product_cost(self) -> int | float: + total_cost = 0 + for product in self.cart: + total_cost += self.cart[product] * self.products[product] + return total_cost -def generate_receipt(cart: dict, products: dict) -> None: - for product in cart: - product_cost = cart[product] * products[product] + def generate_receipt(self) -> None: + for product in self.cart: + product_cost = self.cart[product] * self.products[product] - # removing .0 from product_cost - product_cost = int(product_cost) \ - if product_cost % 1 == 0 else product_cost + # removing .0 from product_cost + product_cost = int(product_cost) \ + if product_cost % 1 == 0 else product_cost - print(f"{cart[product]} {product}s for {product_cost} dollars") + print( + f"{self.cart[product]} {product}s for {product_cost} dollars" + ) def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: @@ -68,7 +76,10 @@ def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: fuel_price, customer.car, distance ) - product_cost = calculate_product_cost(customer.cart, shop.products) + product_cost = Cart( + customer.cart, + shop.products + ).calculate_product_cost() total_spending = round(product_cost + trip_fuel_price, 2) @@ -90,13 +101,13 @@ def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: if customer.money > total_spending: print(f"{customer.name} rides to {closest_shop.name}\n") - # left str date for tests, otherwise: - # datetime.strftime(datetime.now(), "%d/%m/%Y %H:%M:%S") - print("Date: 04/01/2021 12:33:41") + # setting date manually since test checks for const str + date = datetime.strptime("04/01/2021 12:33:41", "%d/%m/%Y %H:%M:%S") + print(f"Date: {datetime.strftime(date, "%d/%m/%Y %H:%M:%S")}") print(f"Thanks, {customer.name}, for your purchase!") print("You have bought:") - generate_receipt(customer.cart, closest_shop.products) + Cart(customer.cart, closest_shop.products).generate_receipt() print( f"Total cost is " f"{shops_trip_cost[closest_shop]['products_cost']} dollars" From cc44f7f311513f6d772451804aa09e48c2b0a5f1 Mon Sep 17 00:00:00 2001 From: DSahalatyi Date: Mon, 2 Sep 2024 16:04:26 +0300 Subject: [PATCH 4/6] fix linter error --- app/shop_trip_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/shop_trip_functions.py b/app/shop_trip_functions.py index a98489e2..6e9ccd6b 100644 --- a/app/shop_trip_functions.py +++ b/app/shop_trip_functions.py @@ -103,7 +103,7 @@ def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: # setting date manually since test checks for const str date = datetime.strptime("04/01/2021 12:33:41", "%d/%m/%Y %H:%M:%S") - print(f"Date: {datetime.strftime(date, "%d/%m/%Y %H:%M:%S")}") + print(f"Date: {datetime.strftime(date, '%d/%m/%Y %H:%M:%S')}") print(f"Thanks, {customer.name}, for your purchase!") print("You have bought:") From 911a932ccc36ee6d5d59a275e2fa64ec22d25a2a Mon Sep 17 00:00:00 2001 From: DSahalatyi Date: Wed, 4 Sep 2024 15:03:30 +0300 Subject: [PATCH 5/6] refactor classes --- app/__init__.py | 0 app/customers/car.py | 11 ++++ app/customers/customer.py | 20 +++--- app/main.py | 21 +++++- app/shop_trip_functions.py | 127 ------------------------------------- app/shops/cart.py | 23 +++++++ app/shops/shop.py | 29 +++++++-- app/trips/__init__.py | 0 app/trips/point.py | 11 ++++ app/trips/trip.py | 66 +++++++++++++++++++ 10 files changed, 164 insertions(+), 144 deletions(-) create mode 100644 app/__init__.py create mode 100644 app/customers/car.py delete mode 100644 app/shop_trip_functions.py create mode 100644 app/shops/cart.py create mode 100644 app/trips/__init__.py create mode 100644 app/trips/point.py create mode 100644 app/trips/trip.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/customers/car.py b/app/customers/car.py new file mode 100644 index 00000000..9d4038f2 --- /dev/null +++ b/app/customers/car.py @@ -0,0 +1,11 @@ +class Car: + def __init__(self, brand: str, fuel_consumption: float) -> None: + self.brand = brand + self.fuel_consumption = fuel_consumption + + def calculate_fuel_spent( + self, + distance: float, + fuel_price: float + ) -> float: + return self.fuel_consumption / 100 * distance * fuel_price diff --git a/app/customers/customer.py b/app/customers/customer.py index 34e4d7fb..8f608420 100644 --- a/app/customers/customer.py +++ b/app/customers/customer.py @@ -1,14 +1,18 @@ +from app.customers.car import Car +from app.trips.point import Point + + class Customer: def __init__( - self, - name: str, - product_cart: dict, - location: list, - money: int | float, - car: dict, + self, + name: str, + product_cart: dict, + location: list, + money: int | float, + car: dict, ) -> None: self.name = name self.cart = product_cart - self.location = location + self.location = Point(*location) self.money = money - self.car = car + self.car = Car(**car) diff --git a/app/main.py b/app/main.py index 3f91a28d..38a5f298 100644 --- a/app/main.py +++ b/app/main.py @@ -1,8 +1,25 @@ -from app.shop_trip_functions import get_data_from_file, print_trip_log +import json +from pathlib import Path + +from app.trips.trip import Trip from app.customers.customer import Customer from app.shops.shop import Shop +base_dir = Path(__file__).resolve().parent +file_name = "config.json" + + +def get_data_from_file() -> tuple: + with open(base_dir / file_name, "r") as file: + file_data = json.load(file) + return ( + file_data["FUEL_PRICE"], + file_data["customers"], + file_data["shops"] + ) + + def shop_trip() -> None: fuel_price, customers, shops = get_data_from_file() @@ -10,4 +27,4 @@ def shop_trip() -> None: shops = [Shop(**shop_info) for shop_info in shops] for customer in customers: - print_trip_log(fuel_price, customer, shops) + Trip(fuel_price, customer, shops).print_trip_log() diff --git a/app/shop_trip_functions.py b/app/shop_trip_functions.py deleted file mode 100644 index 6e9ccd6b..00000000 --- a/app/shop_trip_functions.py +++ /dev/null @@ -1,127 +0,0 @@ -# flake8: ignore=VNE001 -import json -import math -from datetime import datetime -from pathlib import Path -from typing import NamedTuple - -from app.customers.customer import Customer - - -class Point(NamedTuple): - x: int # noqa: VNE001 All my homies hate flake8! - y: int # noqa: VNE001 - - -base_dir = Path(__file__).resolve().parent -file_name = "config.json" - - -def get_data_from_file() -> tuple: - with open(base_dir / file_name, "r") as file: - file_data = json.load(file) - return ( - file_data["FUEL_PRICE"], - file_data["customers"], - file_data["shops"] - ) - - -def calculate_distance(p1: list, p2: list) -> float: - p1 = Point(*p1) - p2 = Point(*p2) - - return math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2) - - -def calculate_fuel_spent( - fuel_price: float, - car: dict, - distance: float -) -> float: - return car["fuel_consumption"] / 100 * distance * fuel_price - - -class Cart: - def __init__(self, cart: dict, products: dict) -> None: - self.cart = cart - self.products = products - - def calculate_product_cost(self) -> int | float: - total_cost = 0 - for product in self.cart: - total_cost += self.cart[product] * self.products[product] - return total_cost - - def generate_receipt(self) -> None: - for product in self.cart: - product_cost = self.cart[product] * self.products[product] - - # removing .0 from product_cost - product_cost = int(product_cost) \ - if product_cost % 1 == 0 else product_cost - - print( - f"{self.cart[product]} {product}s for {product_cost} dollars" - ) - - -def print_trip_log(fuel_price: float, customer: Customer, shops: list) -> None: - print(f"{customer.name} has {customer.money} dollars") - - shops_trip_cost = {} - for shop in shops: - distance = calculate_distance(customer.location, shop.location) - trip_fuel_price = 2 * calculate_fuel_spent( - fuel_price, customer.car, distance - ) - - product_cost = Cart( - customer.cart, - shop.products - ).calculate_product_cost() - - total_spending = round(product_cost + trip_fuel_price, 2) - - print( - f"{customer.name}'s trip to the {shop.name} costs {total_spending}" - ) - - shops_trip_cost[shop] = { - "products_cost": product_cost, - "total": total_spending - } - - closest_shop = min( - shops_trip_cost, key=lambda shop: shops_trip_cost[shop]["total"] - ) - - total_spending = shops_trip_cost[closest_shop]["total"] - - if customer.money > total_spending: - print(f"{customer.name} rides to {closest_shop.name}\n") - - # setting date manually since test checks for const str - date = datetime.strptime("04/01/2021 12:33:41", "%d/%m/%Y %H:%M:%S") - print(f"Date: {datetime.strftime(date, '%d/%m/%Y %H:%M:%S')}") - - print(f"Thanks, {customer.name}, for your purchase!") - print("You have bought:") - Cart(customer.cart, closest_shop.products).generate_receipt() - print( - f"Total cost is " - f"{shops_trip_cost[closest_shop]['products_cost']} dollars" - ) - - customer.money -= total_spending - print("See you again!\n") - - print(f"{customer.name} rides home") - - print(f"{customer.name} now has {customer.money} dollars\n") - - else: - print( - f"{customer.name} doesn't have enough " - f"money to make a purchase in any shop" - ) diff --git a/app/shops/cart.py b/app/shops/cart.py new file mode 100644 index 00000000..844e0aab --- /dev/null +++ b/app/shops/cart.py @@ -0,0 +1,23 @@ + +class Cart: + def __init__(self, cart: dict, products: dict) -> None: + self.cart = cart + self.products = products + + def calculate_product_cost(self) -> int | float: + total_cost = 0 + for product in self.cart: + total_cost += self.cart[product] * self.products[product] + return total_cost + + def generate_receipt(self) -> None: + for product in self.cart: + product_cost = self.cart[product] * self.products[product] + + # removing .0 from product_cost + product_cost = int(product_cost) \ + if product_cost % 1 == 0 else product_cost + + print( + f"{self.cart[product]} {product}s for {product_cost} dollars" + ) diff --git a/app/shops/shop.py b/app/shops/shop.py index 54306878..7afcf0c0 100644 --- a/app/shops/shop.py +++ b/app/shops/shop.py @@ -1,10 +1,25 @@ +from datetime import datetime + +from app.customers.customer import Customer +from app.shops.cart import Cart +from app.trips.point import Point + + class Shop: - def __init__( - self, - name: str, - location: list, - products: dict - ) -> None: + def __init__(self, name: str, location: list, products: dict) -> None: self.name = name - self.location = location + self.location = Point(*location) self.products = products + + def print_shop_log(self, spending: dict, customer: Customer) -> None: + # setting date manually since test checks for const str + date = datetime.strptime("04/01/2021 12:33:41", "%d/%m/%Y %H:%M:%S") + print(f"Date: {datetime.strftime(date, '%d/%m/%Y %H:%M:%S')}") + + print(f"Thanks, {customer.name}, for your purchase!") + print("You have bought:") + Cart(customer.cart, self.products).generate_receipt() + print(f"Total cost is " f"{spending['products_cost']} dollars") + + customer.money -= spending["total"] + print("See you again!\n") diff --git a/app/trips/__init__.py b/app/trips/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/trips/point.py b/app/trips/point.py new file mode 100644 index 00000000..15e1fe6c --- /dev/null +++ b/app/trips/point.py @@ -0,0 +1,11 @@ +# flake8: noqa: VNE001 +from __future__ import annotations +import math + +class Point: + def __init__(self, x: int, y: int) -> None: + self.x = x #noqa: VNE001 + self.y = y #noqa: VNE001 + + def calculate_distance(self, other: Point) -> float: + return math.sqrt((other.x - self.x) ** 2 + (other.y - self.y) ** 2) diff --git a/app/trips/trip.py b/app/trips/trip.py new file mode 100644 index 00000000..d645d2cd --- /dev/null +++ b/app/trips/trip.py @@ -0,0 +1,66 @@ +from app.customers.customer import Customer +from app.shops.shop import Shop +from app.trips.point import Point +from app.shops.cart import Cart + + +class Trip: + def __init__( + self, + fuel_price: float, + customer: Customer, + shops: list[Shop] + ) -> None: + self.fuel_price = fuel_price + self.customer = customer + self.shops = shops + self.cost = {} + + def print_trip_log(self) -> None: + print(f"{self.customer.name} has {self.customer.money} dollars") + + for shop in self.shops: + self.cost[shop] = self.calculate_shop_trip_cost(shop) + + print( + f"{self.customer.name}'s trip to the " + f"{shop.name} costs {self.cost[shop]["total"]}" + ) + + closest_shop = self.find_closest_shop() + + if self.customer.money > self.cost[closest_shop]["total"]: + print(f"{self.customer.name} rides to {closest_shop.name}\n") + + closest_shop.print_shop_log(self.cost[closest_shop], self.customer) + + print(f"{self.customer.name} rides home") + print(f"{self.customer.name} now has " + f"{self.customer.money} dollars\n") + + else: + print( + f"{self.customer.name} doesn't have enough " + f"money to make a purchase in any shop" + ) + + def calculate_shop_trip_cost(self, shop: Shop) -> dict: + distance = Point.calculate_distance( + self.customer.location, + shop.location + ) + trip_fuel_price = 2 * self.customer.car.calculate_fuel_spent( + distance, self.fuel_price + ) + + product_cost = Cart( + self.customer.cart, + shop.products + ).calculate_product_cost() + + total_spending = round(product_cost + trip_fuel_price, 2) + + return {"products_cost": product_cost, "total": total_spending} + + def find_closest_shop(self) -> dict: + return min(self.cost, key=lambda shop: self.cost[shop]["total"]) From 6d6fd708484d45b055e13b5d704ad4940a5e8c21 Mon Sep 17 00:00:00 2001 From: DSahalatyi Date: Wed, 4 Sep 2024 15:05:04 +0300 Subject: [PATCH 6/6] fix linter error --- app/trips/trip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/trips/trip.py b/app/trips/trip.py index d645d2cd..5322e7c8 100644 --- a/app/trips/trip.py +++ b/app/trips/trip.py @@ -24,7 +24,7 @@ def print_trip_log(self) -> None: print( f"{self.customer.name}'s trip to the " - f"{shop.name} costs {self.cost[shop]["total"]}" + f"{shop.name} costs {self.cost[shop]['total']}" ) closest_shop = self.find_closest_shop()