feat: Semaine 8
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
@dataclass
|
||||
class Customer:
|
||||
id: int
|
||||
name: str
|
||||
email: str
|
||||
address: str
|
||||
order_count: int
|
||||
is_premium: Optional[bool] = field(default=None)
|
||||
|
||||
def __post_init__(self):
|
||||
if self.is_premium is None:
|
||||
self.is_premium = self.order_count > 10
|
||||
@@ -0,0 +1,20 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Dish:
|
||||
id: int
|
||||
name: str
|
||||
price: float
|
||||
description: str = ""
|
||||
is_available: bool = True
|
||||
|
||||
def with_new_price(self, new_price: float) -> 'Dish':
|
||||
return Dish(
|
||||
id=self.id,
|
||||
name=self.name,
|
||||
price=new_price,
|
||||
description=self.description,
|
||||
is_available=self.is_available
|
||||
)
|
||||
|
||||
plat_01 = Dish(id=1, name="Spaghetti Carbonara", price=12.99, description="Classic Italian pasta dish with eggs, cheese, pancetta, and pepper.")
|
||||
@@ -0,0 +1,55 @@
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from domain.entities.dish import Dish
|
||||
|
||||
|
||||
@dataclass
|
||||
class Order:
|
||||
id: int
|
||||
customer_id: int
|
||||
restaurant_id: int
|
||||
restaurant_name: str
|
||||
dishes: list[Dish]
|
||||
delivery_address: str
|
||||
created_at: Optional[datetime] = datetime.now()
|
||||
delivery_at: Optional[datetime] = None
|
||||
|
||||
def amount(self):
|
||||
return sum(dish.price for dish in self.dishes)
|
||||
|
||||
def is_late(self):
|
||||
if self.delivery_at is None:
|
||||
return False
|
||||
deadline = order.created_at + timedelta(minutes= self.DELIVERY_DELAY_MINUTES) #type: ignore
|
||||
return datetime.now() > deadline
|
||||
|
||||
def status(self):
|
||||
if self.delivery_at:
|
||||
return "Delivered"
|
||||
elif self.is_late():
|
||||
return "Late"
|
||||
else:
|
||||
return "In delivery progress..."
|
||||
|
||||
def urgency_level(self, delivery_delay, warning_threshold):
|
||||
if self.delivery_at:
|
||||
return "Delivered"
|
||||
minutes = (datetime.now() - order.created_at).total_seconds() / 60 #type: ignore
|
||||
if minutes > delivery_delay:
|
||||
return "severe_delay"
|
||||
elif minutes > warning_threshold:
|
||||
return "light_delay"
|
||||
return "normal"
|
||||
|
||||
@dataclass
|
||||
class OrderWithStatus:
|
||||
order_id: int
|
||||
restaurant_name: str
|
||||
total_amount: float
|
||||
is_late: bool
|
||||
free_delivery: bool
|
||||
is_premium_customer: bool
|
||||
status: str
|
||||
urgency_level: str # normal, light_delay, severe_delay, delivered
|
||||
@@ -0,0 +1,15 @@
|
||||
class OrderNotFoundException(Exception):
|
||||
"""Raised when an order is not found."""
|
||||
|
||||
def __init__(self, order_id: int):
|
||||
self.order_id = order_id
|
||||
super().__init__(f"Order with ID {order_id} not found.")
|
||||
|
||||
class OrderAlreadyDeliveredException(Exception):
|
||||
"""Raised when an order has already been delivered."""
|
||||
|
||||
def __init__(self, order_id: int):
|
||||
self.order_id = order_id
|
||||
super().__init__(f"Order with ID {order_id} has already been delivered.")
|
||||
|
||||
raise OrderNotFoundException(34)
|
||||
@@ -0,0 +1,66 @@
|
||||
from ast import Or
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from data.repositories.protocols.customer_repository_protocol import CustomerRepositoryProtocol
|
||||
from data.repositories.protocols.order_repository_protocol import OrderRepositoryProtocol
|
||||
from domain.exceptions.order_exceptions import OrderAlreadyDeliveredException, OrderNotFoundException
|
||||
from domain.entities.order import Order, OrderWithStatus
|
||||
|
||||
|
||||
class OrderService:
|
||||
DELIVERY_DELAY_MINUTES = 45
|
||||
WARNING_THRESHOLD_MINUTES = 30
|
||||
FREE_DELIVERY_THRESHOLD = 25.0
|
||||
PREMIUM_THRESHOLD = 10
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
order_repo: OrderRepositoryProtocol,
|
||||
customer_repo: CustomerRepositoryProtocol
|
||||
):
|
||||
self.order_repo = order_repo
|
||||
self.customer_repo = customer_repo
|
||||
|
||||
def get_orders_with_status(self, customer_id: int):
|
||||
orders = self.order_repo.find_by_customer_id(customer_id)
|
||||
customer = self.customer_repo.find_by_id(customer_id)
|
||||
result = []
|
||||
|
||||
for order in orders:
|
||||
result.append(
|
||||
OrderWithStatus(
|
||||
order_id= order.id,
|
||||
restaurant_name= order.restaurant_name,
|
||||
total_amount= order.amount(),
|
||||
is_late= order.is_late(),
|
||||
free_delivery= order.amount() >= self.FREE_DELIVERY_THRESHOLD,
|
||||
is_premium_customer= customer.order_count >= self.PREMIUM_THRESHOLD,
|
||||
status= order.status(),
|
||||
urgency_level= order.urgency_level(self.DELIVERY_DELAY_MINUTES, self.WARNING_THRESHOLD_MINUTES)
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
def mark_order_as_delivered(self, order_id: int):
|
||||
order = self.order_repo.find_by_id(order_id)
|
||||
if order is None:
|
||||
raise OrderNotFoundException(order_id)
|
||||
if order.delivery_at is not None:
|
||||
raise OrderAlreadyDeliveredException(order_id)
|
||||
|
||||
order.delivery_at = datetime.now()
|
||||
self.order_repo.update(order)
|
||||
|
||||
customer = self.customer_repo.find_by_id(order.customer_id)
|
||||
|
||||
return OrderWithStatus(
|
||||
order_id= order.id,
|
||||
restaurant_name= order.restaurant_name,
|
||||
total_amount= order.amount(),
|
||||
is_late= order.is_late(),
|
||||
free_delivery= order.amount() >= self.FREE_DELIVERY_THRESHOLD,
|
||||
is_premium_customer= customer.order_count >= self.PREMIUM_THRESHOLD,
|
||||
status= order.status(),
|
||||
urgency_level= order.urgency_level(self.DELIVERY_DELAY_MINUTES, self.WARNING_THRESHOLD_MINUTES)
|
||||
)
|
||||
Reference in New Issue
Block a user