from __future__ import annotations
from typing import TYPE_CHECKING, Any, cast
from uuid import UUID
from eventsourcing.application import Application
from eventsourcing.persistence import JSONTranscoder, Transcoding
from examples.cargoshipping.domainmodel import (
REGISTERED_ROUTES,
Cargo,
HandlingActivity,
Itinerary,
Leg,
Location,
)
if TYPE_CHECKING:
from datetime import datetime
[docs]
class LocationAsName(Transcoding):
type = Location
name = "location"
[docs]
def encode(self, obj: Location) -> str:
return obj.name
[docs]
def decode(self, data: str) -> Location:
assert isinstance(data, str)
return Location[data]
[docs]
class HandlingActivityAsName(Transcoding):
type = HandlingActivity
name = "handling_activity"
[docs]
def encode(self, obj: HandlingActivity) -> str:
return obj.name
[docs]
def decode(self, data: str) -> HandlingActivity:
assert isinstance(data, str)
return HandlingActivity[data]
[docs]
class ItineraryAsDict(Transcoding):
type = Itinerary
name = "itinerary"
[docs]
def encode(self, obj: Itinerary) -> dict[str, Any]:
return obj.__dict__
[docs]
def decode(self, data: dict[str, Any]) -> Itinerary:
assert isinstance(data, dict)
return Itinerary(**data)
[docs]
class LegAsDict(Transcoding):
type = Leg
name = "leg"
[docs]
def encode(self, obj: Leg) -> dict[str, Any]:
return obj.__dict__
[docs]
def decode(self, data: dict[str, Any]) -> Leg:
assert isinstance(data, dict)
return Leg(**data)
[docs]
class BookingApplication(Application[UUID]):
[docs]
def register_transcodings(self, transcoder: JSONTranscoder) -> None:
super().register_transcodings(transcoder)
transcoder.register(LocationAsName())
transcoder.register(HandlingActivityAsName())
transcoder.register(ItineraryAsDict())
transcoder.register(LegAsDict())
[docs]
def book_new_cargo(
self,
origin: Location,
destination: Location,
arrival_deadline: datetime,
) -> UUID:
cargo = Cargo.new_booking(origin, destination, arrival_deadline)
self.save(cargo)
return cargo.id
[docs]
def change_destination(self, tracking_id: UUID, destination: Location) -> None:
cargo = self.get_cargo(tracking_id)
cargo.change_destination(destination)
self.save(cargo)
[docs]
def request_possible_routes_for_cargo(self, tracking_id: UUID) -> list[Itinerary]:
cargo = self.get_cargo(tracking_id)
from_location = (cargo.last_known_location or cargo.origin).value
to_location = cargo.destination.value
try:
possible_routes = REGISTERED_ROUTES[(from_location, to_location)]
except KeyError:
msg = f"Can't find routes from {from_location} to {to_location}"
raise ValueError(msg) from None
return possible_routes
[docs]
def assign_route(self, tracking_id: UUID, itinerary: Itinerary) -> None:
cargo = self.get_cargo(tracking_id)
cargo.assign_route(itinerary)
self.save(cargo)
[docs]
def register_handling_event(
self,
tracking_id: UUID,
voyage_number: str | None,
location: Location,
handing_activity: HandlingActivity,
) -> None:
cargo = self.get_cargo(tracking_id)
cargo.register_handling_event(
tracking_id,
voyage_number,
location,
handing_activity,
)
self.save(cargo)
[docs]
def get_cargo(self, tracking_id: UUID) -> Cargo:
return cast("Cargo", self.repository.get(tracking_id))