diff --git a/python/delivery_controller.py b/python/delivery_controller.py index a829e54..e5fb6f2 100644 --- a/python/delivery_controller.py +++ b/python/delivery_controller.py @@ -23,16 +23,42 @@ class Delivery: on_time: bool +class Notifier: + + def request_feedback(self, delivery: Delivery): + raise NotImplemented() + + def send_eta_update(self, delivery: Delivery, new_eta: int): + raise NotImplemented() + +class SmtpNotifier: + + def __init__(self, gateway: EmailGateway): + self.gateway = gateway + + def request_feedback(self, delivery: Delivery): + message = f"""Regarding your delivery today at {delivery.time_of_delivery}. How likely would you be to recommend this delivery service to a friend? Click here""" + self.gateway.send( + delivery.contact_email, "Your feedback is important to us", message + ) + + def send_eta_update(self, delivery: Delivery, new_eta: int): + message = f"Your delivery to {delivery.location} is next, estimated time of arrival is in {new_eta} minutes. Be ready!" + self.gateway.send( + delivery.contact_email, "Your delivery will arrive soon", message + ) + + class DeliveryController: def __init__( self, delivery_schedule: List[Delivery], - gateway: Optional[EmailGateway], + notifier: Optional[Notifier] = None, maps: Optional[MapService] = None, ): self.delivery_schedule = delivery_schedule - self.email_gateway = gateway or EmailGateway() self.map_service = maps or MapService() + self.notifier = notifier or SmtpNotifier(EmailGateway()) def update_delivery(self, delivery_event: DeliveryEvent): next_delivery = None @@ -45,10 +71,8 @@ def update_delivery(self, delivery_event: DeliveryEvent): if time_difference < datetime.timedelta(minutes=10): delivery.on_time = True delivery.time_of_delivery = delivery_event.time_of_delivery - message = f"""Regarding your delivery today at {delivery.time_of_delivery}. How likely would you be to recommend this delivery service to a friend? Click here""" - self.email_gateway.send( - delivery.contact_email, "Your feedback is important to us", message - ) + self.notifier.request_feedback(delivery) + if len(self.delivery_schedule) > i + 1: next_delivery = self.delivery_schedule[i + 1] if not delivery.on_time and len(self.delivery_schedule) > 1 and i > 0: @@ -63,7 +87,4 @@ def update_delivery(self, delivery_event: DeliveryEvent): next_eta = self.map_service.calculate_eta( delivery_event.location, next_delivery.location ) - message = f"Your delivery to {next_delivery.location} is next, estimated time of arrival is in {next_eta} minutes. Be ready!" - self.email_gateway.send( - next_delivery.contact_email, "Your delivery will arrive soon", message - ) + self.notifier.send_eta_update(next_delivery, next_eta) diff --git a/python/test_delivery_service.py b/python/test_delivery_service.py index 4c77e47..6cb2c86 100644 --- a/python/test_delivery_service.py +++ b/python/test_delivery_service.py @@ -1,13 +1,16 @@ import pytest import datetime -from delivery_controller import DeliveryController, Delivery, DeliveryEvent +from delivery_controller import DeliveryController, Delivery, DeliveryEvent, SmtpNotifier from map_service import MapService, Location location1 = Location(52.2296756, 21.0122287) location2 = Location(52.406374, 16.9251681) location3 = Location(51.406374, 17.9251681) +now = datetime.datetime.now() +one_hour = datetime.timedelta(hours=1) + def test_map_service(): map_service = MapService() @@ -48,7 +51,7 @@ def a_delivery( id=id, contact_email="fred@codefiend.co.uk", location=location, - time_of_delivery=time or datetime.datetime.now, + time_of_delivery=time or now, arrived=False, on_time=False, ) @@ -56,22 +59,11 @@ def a_delivery( def test_a_single_delivery_is_delivered(): - now = datetime.datetime.now() - - delivery = Delivery( - id=1, - contact_email="fred@codefiend.co.uk", - location=location1, - time_of_delivery=now, - arrived=False, - on_time=True, - ) - - update = DeliveryEvent(1, now, location2) + delivery = a_delivery(1) gateway = FakeEmailGateway() - controller = DeliveryController([delivery], gateway) + controller = DeliveryController([delivery], SmtpNotifier(gateway)) - controller.update_delivery(update) + controller.update_delivery(DeliveryEvent(1, now, location2)) assert delivery.arrived is True assert delivery.on_time is True @@ -87,11 +79,19 @@ def test_a_single_delivery_is_delivered(): ) -now = datetime.datetime.now() -one_hour = datetime.timedelta(hours=1) - def test_when_a_delivery_affects_the_schedule(): + """ + In this scenario, we have three deliveries to three locations. + The first is scheduled to happen now, the second in an hour, the third in + two hours. + + When the second delivery is delivered an hour late, we should call the map + service to recalculate our average speed. + + We should send an email to the recipient of delivery 3 with the updated + ETA. + """ deliveries = [ a_delivery(1, time=now, location=location1), @@ -100,8 +100,8 @@ def test_when_a_delivery_affects_the_schedule(): ] gateway = FakeEmailGateway() - maps = FakeMapService(10) - controller = DeliveryController(deliveries, gateway, maps) + maps = FakeMapService(325) + controller = DeliveryController(deliveries, SmtpNotifier(gateway), maps) controller.update_delivery(DeliveryEvent(2, now + (one_hour * 2), location2)) @@ -110,3 +110,8 @@ def test_when_a_delivery_affects_the_schedule(): assert start == location1 assert end == location2 assert time == (one_hour * 2) + + [_,(address, subject, message)] = gateway.sent + + assert subject == "Your delivery will arrive soon" + assert message == f"Your delivery to {location3} is next, estimated time of arrival is in 325 minutes. Be ready!"