Source code for anyblok_wms_base.core.operation.single_outcome

# -*- coding: utf-8 -*-
# This file is a part of the AnyBlok / WMS Base project
#
#    Copyright (C) 2018 Georges Racinet <gracinet@anybox.fr>
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file,You can
# obtain one at http://mozilla.org/MPL/2.0/.
"""Mixins for Operations that take exactly on PhysObj record as input.
"""

from anyblok import Declarations
from anyblok_wms_base.exceptions import (
    OperationError,
    )

Mixin = Declarations.Mixin
Model = Declarations.Model


[docs]@Declarations.register(Mixin) class WmsSingleOutcomeOperation: """Mixin for Operations that produce a single outcome. This is synctactical sugar, allowing to work with such Operations as if Operations couldn't in general produce several outcomes. """ @property def outcome(self): """Convenience attribute to return the unique outcome. """ Avatar = self.registry.Wms.PhysObj.Avatar return Avatar.query().filter_by(outcome_of=self).one()
[docs] def refine_with_trailing_move(self, stopover): """Split the current Operation in two, the last one being a Move This is for Operations that are responsible for the location of their outcome (see the :attr:`destination_field <anyblok_wms_base.core.operation.base.Operation.destination_field>` class attribute) :param stopover: this is the location of the intermediate Avatar that's been introduced (starting point of the Move). :returns: the new Move instance This doesn't change anything for the followers of the current Operation, and in fact, it is guaranteed that their inputs are untouched by this method. Example use case: Rather than planning an Arrival followed by a Move to stock location, One may wish to just plan an Arrival into some the final stock destination, and later on, refine this as an Arrival in a landing area, followed by a Move to the stock destination. This is especially useful if the landing area can't be determined at the time of the original planning, or simply to follow the general principle of sober planning. """ self.check_alterable() field = self.destination_field if field is None: raise OperationError( self, "Can't refine {op} with a trailing move, because it's " "not responsible for the location of its outcomes", op=self) setattr(self, field, stopover) outcome = self.outcome new_outcome = self.registry.Wms.PhysObj.Avatar.insert( location=stopover, outcome_of=self, state='future', dt_from=self.dt_execution, # copied fields: dt_until=outcome.dt_until, obj=outcome.obj) return self.registry.Wms.Operation.Move.plan_for_outcomes( (new_outcome, ), (outcome, ), dt_execution=self.dt_execution)