Un moteur d'applications de logistique avec Python 3, SQLAlchemy, PostgreSQL et AnyBlok.
Présentation disponible en ligne
https://github.com/gracinet/awb-pyconfr-2018/25mn.rst
J'assume…
Avant passer de passer à du concret, un petit mot sur motivation.
On récupère un type, puis les objets physiques de ce type
Prendre son temps sur cet écran.
Insister sur première spécificité (une ligne par objet physique):
>>> PhysObj = registry.Wms.PhysObj >>> livre_type = PhysObj.Type.query().filter_by(code='GR-DUST-WIND-VOL2').one()) >>> exemplaires = PhysObj.query().filter_by(type=livre_type).all() >>> exemplaires [Wms.PhysObj(id=18, type=Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL2')), Wms.PhysObj(id=19, type=Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL2')), Wms.PhysObj(id=20, type=Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL2')), Wms.PhysObj(id=21, type=Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL2')), Wms.PhysObj(id=22, type=Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL2'))]
En plus du type, on dispose d'un système de propriétés flexibles.
>>> exemplaires[0] Wms.PhysObj(id=18, type=Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL2') >>> exemplaires[0].merged_properties() {'lot': '12A345'} >>> exemplaires[0].set_property('expo', True) >>> exemplaires[0].get_property('expo') True
Sous le capot: un champ JSONB, ou des colonnes séparées
Si c'est différent (à manipuler) ce n'est pas la même chose !
Donc un carton de 50, c'est un autre type que pour 50 exemplaires:
>>> carton = PhysObj.Type.query().filter_by(code='GR-DUST-WIND-VOL1/PALETTE').one() >>> PhysObj.query().filter_by(type=carton).count() 0
Et une palette de 80 cartons, c'est encore autre chose que 80 cartons:
>>> palette = PhysObj.Type.query().filter_by(code='GR-DUST-WIND-VOL1/PALETTE').one() >>> PhysObj.query().filter_by(type=palette).all() [Wms.PhysObj(id=20, type=Wms.PhysObj.Type(id=6, code='GR-DUST-WIND-VOL1/PALETTE'))]
Les avatars encodent la présence d'un objet physique quelque part pour un certain laps de temps.
>>> Avatar = PhysObj.Avatar >>> avatars = Avatar.query().filter_by(obj=exemplaires[0]).order_by(Avatar.dt_from).all() >>> [(av.state, av.location.code, str(av.dt_from)) for av in avatars] [('past', 'QUAI ENTRÉE', '2018-10-06 01:00:40.366405+02:00'), ('past', 'CASIER3', '2018-10-06 01:00:40.397054+02:00'), ('present', 'EMBALLAGE', '2018-10-06 01:00:40.416139+02:00'), ('future', 'QUAI SORTIE', '2018-10-07 13:00:40.416139+02:00')]
Les emplacements sont des objets physiques !
>>> avatars[0].location Wms.PhysObj(id=2, code='QUAI ENTRÉE', type=Wms.PhysObj.Type(id=1, code='EMPLACEMENT FIXE'))
Motivation de la séparation entre PhysObj et PhysObj.Avatar :
Motivation de la séparation entre PhysObj et PhysObj.Avatar :
>>> op = avatars[-1].reason >>> op Model.Wms.Operation.Move(id=17, state='planned', input=Wms.PhysObj.Avatar(...), destination=Wms.PhysObj(id=4, code='QUAI SORTIE', ...) >>> op.execute() >>> avatars[-1].state 'present'
et pour finir, expédions !
>>> registry.Wms.Operation.Departure.create(input=avatars[-1], state='done') >>> avatars[-1].state 'past'
Une certaine indirection…
AnyBlok / Wms Base fournit ce qu'il faut pour les quantités de stocks.
- annulées : cancel()
- exécutées : execute()
- commencées : start()
Jusqu'ici, c'était le Blok wms-core. Il y a aussi :
https://anyblok-wms-base.readthedocs.io/en/latest/improvements.html
Beaucoup de choses intéressantes restent à faire :
Je reviens sur l'objectif initial…
>>> palette Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL1/PALETTE') >>> palette_av = Avatar.query().join(Avatar.obj).filter_by(type=palette).one() >>> palette_av.state, palette_av.location.code ('present', 'SALLE1') >>> unpack = registry.Wms.Operation.Unpack.create(input=palette_av, state='done') >>> len(unpack.outcomes) 81 >>> set((avatar.state, avatar.obj.type.code, avatar.location.code) ... for avatar in unpack.outcomes) {('present', 'GR-DUST-WIND-VOL1/CARTON', 'SALLE1'), ('present', 'PALETTE SUPPORT', 'SALLE1')}
>>> palette Wms.PhysObj.Type(id=7, code='GR-DUST-WIND-VOL1/PALETTE') >>> palette.behaviours['unpack'] {'outcomes': [{'forward_properties': ['lot'], 'quantity': 80, 'required_properties': [], 'type': 'GR-DUST-WIND-VOL1/CARTON'}, {'forward_properties': [], 'quantity': 1, 'required_properties': [], 'type': 'PALETTE SUPPORT'}]}}
Space | Forward |
---|---|
Right, Down, Page Down | Next slide |
Left, Up, Page Up | Previous slide |
G | Go to slide number |
P | Open presenter console |
H | Toggle this help |