anyblok_wms_base.core.goods.goods.
Goods
[source]¶Main data type to represent physical objects managed by the system.
The instances of this model are also the ultimate representation of the Goods “staying the same” or “becoming different” under the Operations, which is, ultimately, a subjective decision that has to be left to downstream libraires and applications, or even end users.
For instance, everybody agrees that moving something around does not make it different. Therefore, the Move Operation uses the same Goods record in its outcome as in its input. On the other hand, changing a property could be considered enough an alteration of the physical object to consider it different, or not (think of recording some measurement that had not be done earlier.)
id
= <anyblok.column.Integer object>¶Primary key.
type
= <anyblok.relationship.Many2One object>¶The Goods Type
properties
= <anyblok.relationship.Many2One object>¶Link to Properties
.
See also
Goods Properties for functional aspects.
Warning
don’t ever mutate the contents of properties
directly,
unless what you want is precisely to affect all the Goods
records that use them directly.
Besides their type
and the fields meant for the Wms Base
bloks logic, the Goods Model bears flexible data,
called properties, that are to be
manipulated as key/value pairs through the get_property()
and
set_property()
methods.
As far as wms_core
is concerned, values of properties can be of any
type, yet downstream applications and libraries can choose to make them
direct fields of the Properties
model.
Properties can be shared among several Goods records, for efficiency.
The set_property()
implements the necessary Copy-on-Write
mechanism to avoid unintentionnally modify the properties of many
Goods records.
Technically, this data is deported into the Properties
Model (see there on how to add additional properties). The properties
column value can be None, so that we don’t pollute the database with
empty lines of Property records, although this is subject to change
in the future.
get_property
(k, default=None)[source]¶Property getter, works like dict.get()
.
Actually I’d prefer to simply implement the dict API, but we can’t direcly inherit from UserDict yet. This is good enough to provide the abstraction needed for current internal wms_core calls.
set_property
(k, v)[source]¶Property setter.
See remarks on get_property()
.
This method implements a simple Copy-on-Write mechanism. Namely, if the properties are referenced by other Goods records, it will duplicate them before actually setting the wished value.
anyblok_wms_base.core.goods.type.
Type
[source]¶Types of Goods.
For a full functional discussion, see Goods Type.
id
= <anyblok.column.Integer object>¶Primary key
code
= <anyblok.column.Text object>¶Uniquely identifying code.
As a convenience, and for sharing with other applications.
behaviours
= <anyblok_postgres.column.Jsonb object>¶Goods Types specify with this flexible field how various Operations
will treat
the represented Goods.
See also
Unpack
for a complex example.
The value is a key/value mapping (behaviour name/value).
Warning
direct read access to a behaviour is to be
avoided in favour of get_behaviour()
(see Goods Type hierarchy and behaviour inheritance).
This field is also open for downstream libraries and applications to
make use of it to define some of their specific logic, but care must be
taken not to conflict with the keys used by wms-core
and other bloks
(TODO introduce namespacing, then ? at least make a list available by
using constants from an autodocumented module)
get_behaviour
(name, default=None)[source]¶Get the value of the behaviour with given name.
This method is the preferred way to access a given behaviour.
It resolves the wished behaviour by looking it up within the
behaviours
dict
, and recursively on its parent.
It also takes care of corner cases, such as when behaviours
is
None
as a whole.
anyblok_wms_base.core.goods.goods.
Properties
[source]¶Properties of Goods.
This is kept in a separate Model (and SQL table) to provide sharing
among several Goods
instances, as they can turn out to be
identical for a large number of them.
Use-case: receive a truckload of milk bottles that all have the same expiration date, and unpack everything down to the bottles. The expiration date would be stored in a single Properties instance, assuming there aren’t also non-uniform properties to store, of course.
Applications are welcome to overload this model to add new fields rather
than storing their meaningful information in the flexible
field,
if it has added value for performance or programmming tightness reasons.
This has the obvious drawback of defining some properties for all Goods,
regardless of their Types, so it should not be abused.
On Goods
, the get_property
/
set_property
API will treat
direct fields and top-level keys of flexible
uniformely,
that, as long as all pieces of code use only this API to handle properties,
flexible keys can be replaced with proper fields transparently at any time
in the development of downstream applications and libraries
(assuming of course that any existing data is properly migrated to the new
schema).
id
= <anyblok.column.Integer object>¶Primary key.
flexible
= <anyblok_postgres.column.Jsonb object>¶Flexible properties.
The value is expected to be a mapping, and all property handling
operations defined in the wms-core
will handle the properties by key,
while being indifferent of the values.
Note
the core also makes use of a few special properties, such as
contents
. TODO make a list, in the form of
constants in a module
create
(**props)[source]¶Direct creation.
The caller doesn’t have to care about which properties get stored as
direct fields or in the flexible
field.
This method is a better alternative than
insertion followed by calls to set()
, because it guarantees that
only one SQL INSERT will be issued.
If no props
are given, then nothing is created and None
gets returned, thus avoiding a needless row in the database.
This may seem trivial, but it spares a test for callers that would
pass a dict
, using the **
syntax, which could turn out to
be empty.
set
(k, v)¶anyblok_wms_base.core.goods.goods.
Avatar
[source]¶Goods Avatar.
See in Core Concepts for a functional description.
id
= <anyblok.column.Integer object>¶Primary key.
location
= <anyblok.relationship.Many2One object>¶Where the Goods are/will be/were.
See Location
for a discussion of what this should actually mean.
state
= <anyblok.column.Selection object>¶State of existence in the premises.
see anyblok_wms_base.constants
.
This may become an ENUM once Anyblok supports them.
reason
= <anyblok.relationship.Many2One object>¶Entry point to operational history.
This records the Operation that is responsible for the current
Avatar, including its state
. In practice, it is
simply the latest Operation
that
affected these goods.
It should renamed as outcome_of
or latest_operation
in some
future.
dt_from
= <anyblok.column.DateTime object>¶Date and time from which the Avatar is meaningful, inclusively.
Functionally, even though the default in creating Operations will be to use the current date and time, this is not to be confused with the time of creation in the database, which we don’t care much about.
The actual meaning really depends on the value of the state
field:
past
and present
states, this is supposed to be
a faithful representation of reality.future
state, this is completely theoretical, and
wms-core
doesn’t do much about it, besides using it to avoid
counting several Goods Avatar of the same physical goods
while peeking at quantities in the future
.
If the end application does serious time prediction, it can use it
freely.In all cases, this doesn’t mean that the very same Goods aren’t present at an earlier time with the same state, location, etc. That earlier time range would simply be another Avatar (use case: moving back and forth).
dt_until
= <anyblok.column.DateTime object>¶Date and time until which the Avatar record is meaningful, exclusively.
Like dt_from
, the meaning varies according to the value of
state
:
past
state, this is supposed to be a faithful
representation of reality: apart from the special case of formal
Splits and Aggregates, the goods
really left this location at these date and time.present
and future
states, this is purely
theoretical, and the same remarks as for the dt_from
field
apply readily.In all cases, this doesn’t mean that the very same goods aren’t present at an later time with the same state, location, etc. That later time range would simply be another Avatar (use case: moving back and forth).