This Operation Model inherits from Mixin.WmsSingleInput
anyblok_wms_base.quantity.operation.split.
Split
[source]¶A split of Goods record in two.
Splits replace their input’s Goods
record with
two of them, one having the wished quantity
, along with
Avatars at the same location, while
keeping the same properties and the same total quantity.
This is therefore destructive for the input’s Goods, which is not conceptually satisfactory, but will be good enough at this stage of development.
While non trivial in the database, they may have no physical counterpart in the real world. We call them formal in that case.
Formal Splits are operations of a special kind, that have to be considered
internal details of wms-core
, that are not guaranteed to exist in the
future.
Formal Splits can always be reverted with
Aggregate
Operations,
but only some physical Splits can be reverted, depending on
the Goods Type.
See also
Model.Wms.Goods.Type
for a full discussion including use-cases of formal and
physical splits and reversal of the latter.
In the formal case, we’ve decided to represent this as an Operation for the sake of consistency, and especially to avoid too much special cases in implementation of various concrete Operations.
The benefit is that Splits appear explicitely in the history, and this helps implementing history manipulating methods a lot.
The drawback is that we get a proliferation of Goods records, some of them even with a zero second lifespan, but even those could be simplified only for executed Splits.
Splits are typically created and executed from Splitter Operations
, and that explains the
above-mentioned zero lifespans.
TYPE
= 'wms_split'¶Polymorphic key
wished_outcome
¶Return the Goods record with the wished quantity.
This is only one of outcomes
Return type: | Wms.Goods |
---|
anyblok_wms_base.quantity.operation.aggregate.
Aggregate
[source]¶An aggregation of Goods record.
Aggregate is the converse of Split.
Like Splits, Aggregates are operations of a special kind, that have to be considered internal details of wms_core, and are not guaranteed to exist in the future.
Aggregates replace some records of Goods sharing equal properties and type, with Avatars at the same location with a single one bearing the total quantity, and a new Avatar.
While non trivial in the database, they may have no physical counterpart in the real world. We call them formal in that case.
Formal Aggregate Operations can always be reverted with Splits,
but only some physical Aggregate Operations can be reverted, depending on
the Goods Type. See Model.Wms.Goods.Type
for a full discussion of
this, with use cases.
In the formal case, we’ve decided to represent this as an Operation for the sake of consistency, and especially to avoid too much special cases implementation of various Operations. The benefit is that they appear explicitely in the history.
TODO implement plan_revert_single()
UNIFORM_GOODS_FIELDS
= ('type', 'properties', 'code')¶UNIFORM_AVATAR_FIELDS
= ('location',)¶field_is_equal
(field, goods_rec1, goods_rec2)[source]¶Return True if given field is equal in the two goods records.
This is singled out because of properties, for which we don’t want to assert equality of the properties lines, but of their content.
TODO: see if implementing __eq__ etc for properties would be a bad idea (would it confuse the Anyblok or SQLAlchemy?)
is_reversible
()[source]¶Reversibility depends on the relevant Goods Type.
See Operation
for what reversibility exactly means in that
context.
check_create_conditions
(state, dt_execution, inputs=None, **kwargs)[source]¶Check that the inputs to aggregate are indeed indistinguishable.
This performs the check from superclasses, and then compares all
fields from UNIFROM_AVATAR_FIELDS
on the inputs (Avatars) and
UNIFORM_GOODS_FIELDS
(on the underlying Goods).
anyblok_wms_base.quantity.operation.splitter.
WmsSplitterOperation
[source]¶Mixin for operations on a single input that can split.
This is to be applied after Mixin.WmsSingleInputOperation
.
Use WmsSplitterSingleInputOperation
to get both at once.
It defines the quantity
field to express that the Operation only
works on some of the quantity held by the Goods of the single input.
In case the Operation’s quantity
is less than in the Goods record,
a Split
will be inserted properly in history, and
the Operation implementation can ignore quantities completely, as it will
always, in truth, work on the whole of the input it will see.
Subclasses can use the partial
field if they need to know
if that happened, but this should be useful only in special cases.
partial
= <anyblok.column.Boolean object>¶Record if a Split will be or has been inserted in the history.
Such insertions should happen if the operation’s original Goods have greater quantity than the operation needs.
This is useful because once the Split is executed, this information can’t be deduced from the quantities involved any more.
quantity
= <anyblok.column.Decimal object>¶The quantity this Operation will work on.
Can be less than the quantity of our single input.
(we list only those methods that override the base classes).
before_insert
(state='planned', follows=None, inputs=None, quantity=None, dt_execution=None, dt_start=None, **kwargs)[source]¶Override to introduce a Split if needed
In case the value of quantity
does not match the one from the
goods
field, a Split
is inserted
transparently in the history, as if it’d been there in the first place:
subclasses can implement after_insert()
as if the quantities were
matching from the beginning.
check_execute_conditions
()[source]¶Check that the quantity (after possible Split) is as on the input.
If a Split has been inserted, then this calls the base class
for the input of the Split, instead of self
, because the input of
self
is in that case the outcome of the Split, and it’s normal
that it’s in state future
: the Split will be executed during
self.execute()
, which comes once the present method has agreed.
anyblok_wms_base.quantity.operation.move.
Move
[source]¶Override to use quantity where needed.
revert_extra_fields
()[source]¶Take quantity into account for reversal.
See also this method’s documentation in the base class
.
anyblok_wms_base.quantity.operation.unpack.
Unpack
[source]¶Override to use quantity where needed.
create_unpacked_goods
(fields, spec)[source]¶Create just a record, bearing the total quantity.
See also this method in the base class
TODO: introduce a behaviour (available in spec) to create as many
records as specified. Even if wms-quantity
is installed, it might
be more efficient for some Goods types. Use-case: some bulk handling
alongside packed goods by the unit in the same facility.
anyblok_wms_base.quantity.operation.splitter.
Departure
[source]¶Override making Departure a Splitter Operation.
As with all Splitter Operations
,
Departures can be partial, i.e.,
there’s no need to match the exact quantity held in the underlying Goods
record: an automatic Split will occur if needed.
In many scenarios, the Departure would come after a Move that would bring the goods to a shipping location and maybe issue itself a Split, so that actually the quantity for departure would be an exact match, but Departure does not rely on that.