Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[13.0] Add Dynamic Routing #31

Merged
merged 33 commits into from
Jun 24, 2020

Conversation

guewen
Copy link
Member

@guewen guewen commented Jun 12, 2020

Moved from OCA/stock-logistics-warehouse#788

Description

Standard Stock Routes explain the steps you want to produce whereas the
“Dynamic Routing” defines how operations are grouped according to their final
source and destination location.

This allows for example:

  • To parallelize transfers in two locations of a warehouse, splitting
    them in two different operation type
  • To define pre-picking (wave) in some sub-locations, then roundtrip picking of
    the sub-location waves

Context for the use cases:

In the warehouse, you have a High-Bay which requires to place goods in a
handover when you move goods in or out of it. The High-Bay contains many
sub-locations.

A product can be stored either in the High-Bay, either in the Shelving zone.

When picking:

When there is enough stock in the Shelving, you expect the moves to have the
usual Pick(Highbay)-Pack-Ship steps. If the good is picked from the High-Bay, you will
need an extra operation: Pick(Highbay)-Handover-Pack-Ship.

This is what this feature is doing: on the High-Bay location, you define
a "routing rule". A routing rule selects a different operation type for the move.
The extra transfer will have the selected operation type, and be added
dynamically, on reservation, before the chain of moves.

When putting away:

A put-away rule targets the High-Bay location.
An operation Input-Highbay is created. You expect Input-Handover-Highbay.

You can configure a dynamic routing for the put-away on the High-Bay Location.
The operation type of the new Handover move will the one of the matching routing rule,
and its destination will be the destination of the operation type.

Try on runbot

  • In Inventory Settings, activate:

    • Storage Locations
    • Multi-Warehouses
    • Multi-Step Routes

The initial setup in the demo data contains locations:

  • WH/Stock/Highbay
  • WH/Stock/Highbay/Bin 1
  • WH/Stock/Highbay/Bin 2
  • WH/Stock/Handover

The "Highbay" location (and children) is configured to:

  • create a pull routing transfer from Highbay to Handover when
    goods are taken from Highbay (using a new picking type Highbay → Handover)
  • create a push routing transfer from Handover to Highbay when
    goods are put to Highbay (using a new picking type Handover → Highbay)

Steps to try the Pull Routing Transfer:

  • In the main Warehouse, configure outgoing shipments to "Send goods in output and then deliver (2 steps)"
  • Inventory a product, for instance "[FURN_8999] Three-Seat Sofa", add 50 items in "WH/Stock/Highbay/Bay A/Bin 1", and nowhere else
  • Create a sales order with 5 "[FURN_8999] Three-Seat Sofa", confirm
  • You'll have 3 transfers; a new one has been created dynamically for Highbay -> Handover.

Steps to try the Push Routing Transfer:

  • In the "WH/Stock" location, create a Put-Away Strategy with:

    • "[DESK0004] Customizable Desk (Aluminium, Black)" to location "WH/Stock/Highbay/Bay A/Bin 1"
    • "[E-COM06] Corner Desk Right Sit" to location "WH/Stock/Shelf 1"
  • Create a new purchase order of:

    • 5 "[DESK0004] Customizable Desk (Aluminium, Black)"
    • 5 "[E-COM06] Corner Desk Right Sit"
  • Confirm the purchase

  • You'll have 2 transfers:

    • one to move DESK0004 from Supplier → Handover and E-COM06 from Supplier → Shelf 1
    • one waiting on the other to move DESK0004 from Handover → WH/Stock/Highbay/Bay A/Bin 1 (the final location of the put-away)

guewen and others added 30 commits June 12, 2020 09:27
* if the move's dest location is a child of the routing's dest location:
  it's more precise so change only the picking type
* if the move's dest location is a parent of the routing's dest
  location: change the dest location to the routing's dest location and
  change the picking type
* if the move's dest location is outside of the routing's dest location:
  add a routing operation before

It means, when there is a routing, even if the location was already
correct, the picking type is changed so users handle transfers the
same way.

The same changes will be done on the destination routing
We can probably optimize it by appling the domain only once
for all the moves of a routing.
The same thing should be applied on destination routing.
when we have to apply a routing instead of using unreserve: any
side-effect will be cancelled before doing the routing and calling
assign again, thus we avoid leaving things behind.
The relation from the move doesn't always exist, if we delete the
package level before the unreserve, they are properly deleted.
Rules can be ordered and excluded by domains.
Store the rule chosen for a move to avoid doing it twice.
A split must occur to handle the routing only on the available quantity.
When a move source location changes or a new move is inserted in the
chain, reevaluate the routing rules so we can chain several rules.
The _split method expects product_qty, not product_uom_qty.
So get the missing reserved quantity and convert it in the unit of
product_qty (as done in StockMove._action_assign())
In some conditions, new_moves can contain the same moves as self, so
_action_assign() would be called twice on the same move and would have
duplicate move lines.
No longer needed after the last refactoring
* Prevent calling _action_assign() twice in case the savepoint was
  released
* Do not apply routing rules on the move we just routed as the routing
  rule to apply will be the same and already done
* Add comments explaining why they are called
In case of a put-away, when using a push routing rule, we want
to keep the expected destination.

For instance, we have a move:

* Input -> Highbay (draft)

It's assigned and the put-away rules compute a move line going to
Highbay/X1Y2.

When a routing is applied, before this commit, it would add a move at
the end, it would look like:

* Input -> Handover (assigned)
* Handover -> Highbay (confirmed)

On reservation of the second move (Handover -> Highbay), it would
compute again the put away rules to find a place in the whole highbay.

With the change now, the moves would look like:

* Input -> Handover (assigned)
* Handover -> Highbay/X1Y2 (confirmed)

So the move line cannot go elsewhere.

To implement this, I decided to remove the 'routing_rule_id' field
stored on 'stock.move', as this field is only needed by the methods
_apply_routing_rule_pull/push and never afterwards. The original
location has to be propagated to these methods as well, so now there
is a single dict of values used to apply the rules.
When an ormcache is cleared, it propagates the invalidation to other
workers, blowing all their caches for all models. Since we use this
cache only for the duration of a method, it's pointless.
By using the parent path of the records, we can avoid many SQL
requests to compare children or find parent locations
The picking type must be selected to filter on routing to apply
There is no real reason to force using the exact same location.
A sub-location should be fine.
guewen added 2 commits June 12, 2020 09:27
On stock.move, the `package_level_id` field did not have a `copy=False`
attribute when version 13.0 of Odoo was released. So when we create
a new move, the package level of the move being copied was linked
as well to the new move.

It has been fixed recently in odoo in
odoo/odoo@ecf726a
but to be on the safe side if the code is not up-to-date,
it's anyway better to force a False value.
Copy link
Contributor

@simahawk simahawk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧠 on 🔥 😅

stock_dynamic_routing/__manifest__.py Outdated Show resolved Hide resolved
stock_dynamic_routing/models/stock_routing.py Show resolved Hide resolved
# by the method.
move.with_context(exclude_apply_dynamic_routing=True)._action_assign()

pickings_to_check_for_emptiness._dynamic_routing_handle_empty()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, the routed moves are assigned 3 times.
The first, which is rollbacked, to know if yes or no a routing needs to be applied.
A second, right after the routing is applied, to ensure the reserved products are the same as during the 1st action_assign call.
And finally a third in the original _action_assign call.
To avoid this 3rd one, we could here return the routed moves.
Then in _split_and_apply_routing we could return something like moves - routed_moves.
Then, only the moves, which already had their routing applied will be returned to _action_assign'. So at the end, _action_assign` will have been called :
once for moves with no routing rules.
twice (one roll backed) on moves that already had been routed before
twice on the moves that just had been routed. (instead of 3 times).

What do you think?

Else it seems all good to me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method _action_assign ignores moves with a state assigned and we know the routed moves have this state (they would not be routed if not assigned, and they can't be partially available because they are split to be available).

@OCA-git-bot
Copy link
Contributor

This PR has the approved label and has been created more than 5 days ago. It should therefore be ready to merge by a maintainer (or a PSC member if the concerned addon has no declared maintainer). 🤖

@simahawk
Copy link
Contributor

@guewen would you like to squash some commits?

@jgrandguillaume
Copy link
Member

/ocabot merge nobump

@OCA-git-bot
Copy link
Contributor

On my way to merge this fine PR!
Prepared branch 13.0-ocabot-merge-pr-31-by-jgrandguillaume-bump-nobump, awaiting test results.

@OCA-git-bot OCA-git-bot merged commit 5c3e1be into OCA:13.0 Jun 24, 2020
@OCA-git-bot
Copy link
Contributor

Congratulations, your PR was merged at 7353e97. Thanks a lot for contributing to OCA. ❤️

sebalix pushed a commit to sebalix/wms that referenced this pull request Aug 10, 2020
…rontend

Location content transfer frontend
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants