| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 | package model// TODO: It would make sense to have this in its own package. Unfortunately,// then there would be a circular dependency between the cargo and handling// packages since cargo.Delivery would use handling.HandlingEvent and// handling.HandlingEvent would use cargo.TrackingID. Also,// HandlingEventFactory depends on the cargo repository.//// It would make sense not having the cargo package depend on handling.import (	"errors"	"time")// HandlingActivity represents how and where a cargo can be handled, and can// be used to express predictions about what is expected to happen to a cargo// in the future.type HandlingActivity struct {	Type         HandlingEventType	Location     UNLocode	VoyageNumber VoyageNumber}// HandlingEvent is used to register the event when, for instance, a cargo is// unloaded from a carrier at a some location at a given time.type HandlingEvent struct {	TrackingID TrackingID	Activity   HandlingActivity}// HandlingEventType describes type of a handling event.type HandlingEventType int// Valid handling event types.const (	NotHandled HandlingEventType = iota	Load	Unload	Receive	Claim	Customs)func (t HandlingEventType) String() string {	switch t {	case NotHandled:		return "Not Handled"	case Load:		return "Load"	case Unload:		return "Unload"	case Receive:		return "Receive"	case Claim:		return "Claim"	case Customs:		return "Customs"	}	return ""}// HandlingHistory is the handling history of a cargo.type HandlingHistory struct {	HandlingEvents []HandlingEvent}// MostRecentlyCompletedEvent returns most recently completed handling event.func (h HandlingHistory) MostRecentlyCompletedEvent() (HandlingEvent, error) {	if len(h.HandlingEvents) == 0 {		return HandlingEvent{}, errors.New("delivery history is empty")	}	return h.HandlingEvents[len(h.HandlingEvents)-1], nil}// HandlingEventRepository provides access a handling event store.type HandlingEventRepository interface {	Store(e HandlingEvent)	QueryHandlingHistory(TrackingID) HandlingHistory}// HandlingEventFactory creates handling events.type HandlingEventFactory struct {	CargoRepository    CargoRepository	VoyageRepository   VoyageRepository	LocationRepository LocationRepository}// CreateHandlingEvent creates a validated handling event.func (f *HandlingEventFactory) CreateHandlingEvent(registered time.Time, completed time.Time, id TrackingID,	voyageNumber VoyageNumber, unLocode UNLocode, eventType HandlingEventType) (HandlingEvent, error) {	if _, err := f.CargoRepository.Find(id); err != nil {		return HandlingEvent{}, err	}	if _, err := f.VoyageRepository.Find(voyageNumber); err != nil {		// TODO: This is pretty ugly, but when creating a Receive event, the voyage number is not known.		if len(voyageNumber) > 0 {			return HandlingEvent{}, err		}	}	if _, err := f.LocationRepository.Find(unLocode); err != nil {		return HandlingEvent{}, err	}	return HandlingEvent{		TrackingID: id,		Activity: HandlingActivity{			Type:         eventType,			Location:     unLocode,			VoyageNumber: voyageNumber,		},	}, nil}
 |