package inventory import "time" // A walk says when it starts and when it ends (novox/hq ADR 0308 decision 1): the save that starts it and the // save that ends it are marked, so `plan-moved` names what the walk touches, its bound and its outcome on those // two saves, and on no other. The marks are kept in the walk's times, so a controller replaced mid-walk (a core // walk replaces it) neither says a start again nor misses the end. // The moments of a walk `plan-moved` names. const ( WalkStarted = "started" WalkEnded = "ended" ) // The outcomes of an ended walk (ADR 0308 decision 1). const ( WalkDelivered = "delivered" WalkFailed = "failed" WalkStopped = "stopped" ) // Live says the walk is walking: cut, not waiting for its delivery's word, and not ended. func (p Plan) Live() bool { return p.Open() && !p.Batch() && !p.Waiting() } // Ended says the walk is in a state it does not leave by itself: done, failed or superseded. func (p Plan) Ended() bool { return p.State == PlanDone || p.State == PlanFailed || p.State == PlanSuperseded } // Outcome is how an ended walk ended: delivered when done; stopped when a person or the delivery's owner stopped // it, or a newer walk took it over; failed otherwise. Empty for a walk not ended. func (p Plan) Outcome() string { switch { case p.State == PlanDone: return WalkDelivered case p.State == PlanSuperseded: return WalkStopped case p.State == PlanFailed && p.Delivery != nil && p.Delivery.Stopped != "": return WalkStopped case p.State == PlanFailed: return WalkFailed } return "" } // markWalk marks the save that starts or ends the walk, in its times and in WalkSaid, and returns what undoes // the mark should the save not be written. A walk starts on the first save that finds it live — when it is cut // and needs no word, or when it is let go — which is before its first tier is asked, and so before anything is // sent: what it restarts is held from its first send on. It starts again when a failed walk is retried. It ends // on the first save that finds it ended after it started; one that ends without ever starting (a batch that // moved nothing, a walk stopped while it waited for its word) touched nothing and says neither. A walk kept // before its times were (ADR 0282 decision 6) is not marked; a release plan is, its times holding only these. func (p *Plan) markWalk(now time.Time) (undo func()) { p.WalkSaid = "" if p.Batch() || (p.Times == nil && p.Release == nil) { return func() {} } var was *PlanTimes if p.Times != nil { kept := *p.Times was = &kept } times := PlanTimes{} if p.Times != nil { times = *p.Times } at := now.UTC() switch { case p.Live() && (times.Started == nil || times.Ended != nil): times.Started, times.Ended = &at, nil p.WalkSaid = WalkStarted case p.Ended() && times.Started != nil && times.Ended == nil: times.Ended = &at p.WalkSaid = WalkEnded default: return func() {} } p.Times = × return func() { p.Times, p.WalkSaid = was, "" } }