Openerp WMS: Draft Proposal To Clean Existing Openerp Models - V8 Work in Progress..
Openerp WMS: Draft Proposal To Clean Existing Openerp Models - V8 Work in Progress..
Openerp WMS: Draft Proposal To Clean Existing Openerp Models - V8 Work in Progress..
Work in Progress...
This analysis is a collaborative effort between
Camptocamp
and
OpenERP SA
.
Legend:
● Pending Questions/Issues
● Something has to be developed
1. Introduction
List of Concepts
2. Analysis of Concepts
2.1 Routing of Products: Stock Movements
2.1.1 Concepts Explained
2.1.1.1 Stock movements: stock.move
2.1.1.2 Push rules:
2.1.1.3 Pull rules:
2.1.1.4 Notes on Pull and Push rules
2.1.1.5 Removal strategies
2.1.1.6 Put away strategies
2.1.1.7 Routes
2.1.1.8 Cancellation of an operation in a chain
2.1.1.9 Change of quantities in a chain
2.1.1.10 Procurement Group
2.1.1.11 Impact on pickings
2.1.2 Use cases
2.1.2.1 Incoming Shipments, with input = stock
2.1.2.2a Incoming shipments with input != stock
2.1.2.2b Reception with a purchase order coming from a procurement on
stock
2.1.2.3 Simple outgoing shipments (ship only)
2.1.2.4 Outgoing shipments (pack + ship)
2.1.2.5 Outgoing with pick → pack → ship
2.1.2.6: Sale → Purchase and MTO (drop shipping)
2.2 Pickings
2.2.1 Concept explained
2.2.1.1 Introduction to pickings
2.2.1.2 Picking and push rules
2.2.1.3 Picking and pull rules
2.2.2 Use Cases
2.2.2.1: CrossDocking
1/51
Aside Notes on Pegging strategy
2.2.2.2: routing at reception
2.3 Picking Waves
2.3.1 Concept of picking wave
2.3.2 Use Cases
2.3.2.1 Batch picking
2.3.2.2. Wave Picking
2.3.2.3 Trip assignation
2.4 Quants
2.4.1 Concept Explained
2.4.1.2 Consumables vs Stockable products
2.4.2 Use Cases
2.4.2.1 examples of some moves
2.4.2.2 How is it used in lots management
2.4.2.3 How is it used in FIFO
2.4.2.5: negative stocks
2.4.2.7 Impact on performance
2.4.3 Separation of concepts
2.5 Lots Management
2.6 Packings
Data Model: packaging
Removal Strategies
Packing in stock.picking
Some notes on the interface
Examples
Use case 1: reception
Use case 2: Pick
Use Case 3: pack
Use Case 4: Ship
Use Case 5: Partial Pick
Viewing a pack (stock.quant.pack)
Pack (stock.quant.pack) and putaway strategies
2.7 Real Time Costing
2.7.1 Basics
2.7.1.1 ‘Standard Price’ costing method
2.7.1.2 ‘Average Price’ costing method
2.7.1.2 ‘Real Costs’ costing method (FIFO, LIFO)
2.7.2 Stock valuation reconciliation
2.7.3 Landed costs
2.7.4 Anglo saxon accounting
2.7.5 Stock Ownership
2.7.6 Implementation
2.8 MultiCompany
2.8.1 Explanation of the current problem
2.8.2 Things to do to in order to solve this problem
2.9 Burst Process
2/51
2.10 Dates Management
2.11 Replenishment strategy
2.12 KPI
2.13 Purchase Order Workflow and Procurements
Use Case: Reception → Quality Control → Stock (pull)
Modularity
List of Corner cases to take care of
Negative Quants
Identified Issues
Misc points
Raised points to include in the doc
3/51
1. Introduction
List of Concepts
● Put Away Strategies
● Removal Strategies
● Push Rules
● Pull Rules
● CrossDock
● Picking
● Packing
● Procurements
● Stock Moves
● Routes
● Batch Picking
● Wave Picking
● Quants
● FIFO
2. Analysis of Concepts
4/51
(source and destination)
● Done:
the stock move has been done (products have been moved)
This concept already exists in OpenERP.
2.1.1.2 Push rules:
A rule that trigger another stock.move based on a stock.move.
● Example : When products arrive in “Input” location, you want to move them to
“stock” directly with a push rule (this example intentionally simplifies the flow by not
taking eventual quality checks into account)
So, when a stock.move “Supplier → Input” is confirmed, this rule will create another
stock.move: “Input → Stock”. It allows 3 mode: automatic (the second operation will be
validated automatically), manual (the second operation must be validated manually),
manual no step added. (the destination of the first move is replaced instead of creating
another stock.move.
Push rules can be defined on products or locations (or combinations of both).
When several push rules are triggered at the same time (by action_confirm on
stock.picking), we must be sure that all chained moves that have the same destination
location are grouped in the same picking. (according to group concept explained later)
This concept already exists in OpenERP.
5/51
This concept already exists in OpenERP but we should also add the concept of group of
picking
2.1.1.4 Notes on Pull and Push rules
1. Neither the pull nor the push rules propagate a change in the quantity on a stock
move
Example : i ordered 5 products to a supplier and have a manual push rule from input to
stock, in the system. I have the given chained stock moves: supplier → input → stock
Given that i see there is a broken piece in the incoming shipment when i receive the
products, I have 2 possibilities:
1°) i make the partial reception and it creates a backorder for the remaining product. The
next chained move stays in ‘Waiting’ while all backorders are not ‘Done’. This is the
current behavior.
2°) i want to accept the current reception fully so that the rest of the flow can proceed
further without waiting for a new shipment from my supplier, if i change my quantity on the
initial stock move (supplier → input) it won’t be propagated.
In this second case, the behavior is normal because imagine you were doing
crossdocking operation and forwarding the goods to the client directly (supplier → input →
output → customer): you certainly don’t want to automatically deliver your customer all but
one product, as you may have another product from stock to replace the missing one. This
case is an exception in the logistics flow and must be treated manually (as does OpenERP
for all exception cases).
There are scenario where we want to propagate changes in quantities and split of moves
(reception) and others where we don’t want to propagate (picking → packing or picking →
mo).
We should probably define on the stock.move if we propagate changes or not. This is
probably linked to the existing feature: propagate cancel of moves. So, we should reuse
and extend this to propagate split and quantity changed, not only cancellation.
Remark : Currently, we have cancel_cascade on moves, but this can only be triggered by
pull moves (it is False for push moves). The problem with the pull rules is that the
cancellation advances forward, while it should advance in the backwards direction. (=> if
you cancel a picking, it will cancel the delivery order, but if you cancel the delivery order, it
won’t cancel the picking and it should be the other way around)
2. Chained moves propagate the quant (and thus the lot number)
Chained locations propagate the quants. Both push and pull rules chain locations. So, the
lot number (which is referenced on the quant) is propagated for both push and pull rules.
6/51
When a stock.move is done, the quant is selected (if not provided manually) and, by
default, it reuses the quant of the preceding chained move.
3. Push/Pull rules aren’t new but may need to be improved
To add some flexibility, power … for example it may be interesting to
● add the possibility to define a push/pull rule from a product category (means we
chose the rule to apply/create at category level, and the product aggregates the
rules from his categories (recursively)) .
● Push/pull rules should also work on a product attribute
○ A Further deeper analysis will cover this point. (TODO)
4. (We may need to add a big picture of pull/push rules)
We think that it may be interesting to show in a clear way all routes defined in the system
as pull/push rules, ideally in the form of a diagram view.
We need a related button on the product form that opens all push/pull rules that may
impact this product. (from the product, it’s category, rules on locations, …) This list view
can be converted into a diagram view to see it graphically.
This isn’t necessary at all and can come at last. I let it here for the record only
5. Pull rules doesn’t seem to work with non stockable products.
There exists a bug currently to fix: pull rules aren’t working with non stockable products
(maybe only in MTS, not sure)
2.1.1.7 Routes
A route is a set of rules (push and/or pull). On products and categories of products, we
assign routes (many2many_tags), not directly push/pulll rules.
The worst of the push/pull rules today are the configuration of them. Very difficult to set
and manage a large quantity of product and be sure that everyone has the proper rules.
Route will allow to easily reuse a set of rules.
Routes for basic configurations could also be defined by default to help the setup of
warehouses flows. (this shouldn’t be done at first)
This concept does not exists in OpenERP and need to be developped: a route is just a
name, and 2 many2many fields: one containing all the push rules of the route, the other
one all the pull rules of the route.
9/51
pick location. OpenERP also supports to propagate cancellation. So, we will need to
configure pull/push rules accordingly:
● input → stock (propagate)
● pick → pack (do not propagate)
● pack → delivery (propagate)
● input → crossdock (propagate)
This feature already exists in OpenERP but should be extended to also propagate
changes in quantities and split of stock.move.
10/51
picking by a function field computed based on its related stock.move. This will have
several impacts:
● change the way purchases monitor receptions (listen to stock.move, not picking)
● change everything that was related to the picking workflow (mrp.production,
repairs, …)
Confirmed: Supplier Stock
● When we change the state of the stock.move to assigned, a put away rule will
select the right destination location within children location of “stock” according to
the put away strategy.
Assigned: Supplier Stock \ Bin A
(*) = Put Away strategy
To develop:
● Implement put away strategies to select the right location according to different
criteria: location capacities, complete existing bin with same product, …
● Purchase orders should create stock.move, in “ confirmed ” state, not in assigned
state. (because the destination (using put away strategy) has to be done when
receiving the products, not when confirming the purchase)
Note that this can be managed with push rules (with no step added) for very simple rules
(this product goes into this location).
2.1.2.2a Incoming shipments with input != stock
Scenario with:
11/51
● Purchase order recorded manually
● incoming shipment is received on an input location first (e.g. at the docks) before
the goods go to a specific location in the stock.
Configuration:
● Location Structure:
○ Warehouse
■ Input (quai de déchargement)
■ Stock
● On the warehouse, you have “input location” equals to “Input”
The steps:
● When the purchase order is validated, a stock.move is created (in state: confirmed)
Confirmed: Supplier Input
● This stock.move triggers a push rule (input → Stock) that creates the following
move:
Waiting: Input Stock
● At the product reception, we execute the first move and assign the second move,
we get:
Done: Supplier Input
Assigned: Input Stock \ Bin A
(*) Put Away strategy
The user can also change the destination manually, selecting another destination location
(e.g. bin) on the document.
2.1.2.2b Reception with a purchase order coming from a procurement on stock
A procurement on stock should trigger:
● Pull rule 1: move: Input → Stock (MTO)
● Pull rule 2: po: supplier → input
To develop:
● Nothing more than previous use case
This means we need to create 3 rules to handle reception through an input lnput location
(one for manual orders (push) and two from pulled flows)
12/51
Confirmed: Stock Customer
● When we assign it, we get:
Assigned: Stock Customer
(*) Removal Strategy
To develop:
● Need to implement other removal strategies than nearest first
● Split when stock comes from different sublocations (see below)
Confirmed: Output Customer
13/51
● The pull rules will generate a move from packing zone to output and another one
from stock to packing zone, both chained together.
Waiting: Packing Zone Output
Waiting: Stock Packing Zone
● When the second move becomes assigned, it selects the right sublocation of
stock:
Waiting: Packing Zone Output
Assigned: Stock / Bin A Packing Zone
(*) Removal strategy
● Whenever the second stock move gets done, the stock move from packing zone to
output becomes assigned:
Assigned: Packing Zone Output
Done: Stock / Bin A Packing Zone
(*) Removal strategy
14/51
Output Customer
Pull1 : Does not need to be a pull rule itself from Stock to Picked. It can be
triggered by an orderpoint instead which can make sure the packer has enough to
pack, but does not lead to an uncluttered pack of goods next to the packer.
Pull2: Packed pulls from Picking
Pull3: Output pulls from Packed
● When we execute the flow, all the pickings get towards assigned/done. When they
get assigned, they could get a different location because of Put Away (or Removal
Strategies only on first move):
15/51
2.2 Pickings
2.2.1 Concept explained
16/51
Outgoing. We think this should be removed to allow supporting more types of movements:
● Receptions
● CrossDock
● DropShipping
● Pick
● Pack
● Shipping
● Quality Control, ...
So, we will create a new object handling the different picking types (stock.picking.type) and
different values must be stored on this object, rather than computed in the code (e.g.
default source location, default destination location)
The Picking Type (describing what operation you want to do) should be the entry point in
the application as we don’t have the 3 menus anymore (Incoming, outgoing, internal). We
need a clean kanban view that replaced the menu showing all possible operations and key
metrics about what to do and performance. (like sales team in trunk, sales module)
2.2.2.1: Cross-Docking
Configuration of Locations:
● Input: reception of goods
● Crossdock: zone where goods are temporarily waiting for out
● Stock
○ Bin A/B/...
● Picked (where goods are put after picking)
● Packed (where goods are put after packing)
● Output
Scenario 1: routes are defined according to the product
We will give the example of fresh products that always do crossdock and plastic cups that
always go to stock.
In case of plastic cups, we will always go to stock:
17/51
In case of fresh products, we will always do crossdock:
Then, the exact sequence of steps are:
● SO triggers: Output → Customer
● Then several pull rules according to products trigger:
○ Packed → Output
○ Input →Crossdock → Output (for fresh products)
● Then pull rules according to locations
○ Stock → Picked →Packed
○ Supplier → Input (through a PO: pull rule of type ‘buy’)
Steps:
● Sales order with fresh products that will be crossdocked and plastic cups.
Waiting: Output → Customer with fresh products and plastic cups
● 1 purchase order from the same supplier with fresh products and plastic cups:
Confirmed: Supplier → Input with fresh products and plastic cups
● It will split in two pickings as fresh products always do crossdock and plastic cups
do not. So there will be pull rules on the product from Crossdock→ output and
from Input →Crossdock
Confirmed: Input → Stock → Picked → Packed → Output with plastic cups
Confirmed: Input → Crossdock → Output with fresh products
● Put Away Strategy on Stock when first move gets assigned and when second
move gets assigned it will do the removal strategy and as it is the only stock, it will
take from the stock we entered:
Confirmed: Input → Stock / Bin A → Picked → Packed → Output
Confirmed: Input → Crossdock → Output with fresh products
Scenario 2: routes are defined at reception by the warehouse manager:
18/51
(*) with autopropagation of cancel
(**) pull for scenario 1, push for scenario 2 (if there is a pull, the push does not apply)
● Multiple sales orders with plastic and glass cups
SO A: Waiting: Output → Customer with glass and plastic cups (two full
pallets, one plastic, one glass)
SO B: Waiting: Output → Customer with glass and plastic cups (2 boxes
and a half of glass cups and half a box of plastic cups)
● One big purchase order with plastic and glass cups to the same supplier. (two full
homogeneous pallets and one mixed pallet)
Supplier → Input → Stock →Picked →Packed →Output →Customer
● Then the warehouse manager will decide that SO B needs to go to stock and
packing because the truck will only arrive tomorrow and it becomes too cluttered on
the floor. It is also better to provide 3 boxes instead of one pallet on the truck
(packing).
● => Warehouse Manager decides that the two pallets have to go through
CrossDock and the 3 boxes will go to stock
This will split the moves, and for the 2 pallets, the original flow will be cancelled:
2 pallets: Input → Crossdock → Output (and the previous flow will be cancelled)
3 boxes: Input →Stock →Picked →Packed →Output
Our proposition is to create all location by default (may be in stock_location module), the
default routes (pick>pack>ship, crossdock, drop ship, …). So that it’s very easy to do a
demo or configure the system without having to create all locations and rules (just set the
route on the product)
Scenario 3: removal strategy that decides where we can take the products (stock or
crossdock)
● I do not know if it’s feasible in our solution? Describe the sequence of steps
● Sales order
Stock/Input > Output > Customer
● Purchase order
Supplier > Input
● Removal strategy on Stock / Input. It will decide a specific location in Stock / Input
19/51
(disadvantage: confuses concepts of location / bin (or bin locations) )
TODO: Scenario depending on MTO/MTS for different lines of a sale order
Question:
● So, when having received products, there are two possibilities:
○ We leave the products waiting for the execution of an outgoing shipment as
we expect its transport soon or it is over there already
○ We move the products towards the stock in order to keep the docks empty
● An important question here is whether we can define beforehand which products
will do crossdock and which will not. If we know we will do crossdocking by
advance, and if we are used to, then we can manage this by a pull rule from output
to input.
Note that:
● The stock.pickings above could be split in several pickings when there will be
products that are ready for crossdock and other products that do not. It is possible
that the warehouse manager decides to bring certain products in stock or products
in crossdock.
● Our future solution must allow the warehouse manager to decide case by case and
override the picking proposed by push/pull rule and solve this problem in an
efficient way (cancellation propagation?). For more details, see the small note on
Pegging Strategy just below.
Aside Notes on Pegging strategy
Pegging is the links between requirements with suitable stocks or receipts.
The pegging strategy if consequently the regulation that determines the time sequence in
which the system processes requirements in dynamic pegging and the time sequence in
which the system assigns the receipt elements in the pegging interval to a requirement.
The pegging strategy therefore controls:
● which requirement the system processes first
● which receipts the system uses first
In particular,
● it does the matching between IN/OUT operations
● it handles reserved, released and priority changes
● If you have on unit of product A in your stock, you sell one unit to customer A, one
unit on customer B. If you first validate your Customer A, then B => then you have
a available picking for Customer A. The picking for Customer B is waiting. Then if
you want now to invert the priority, because customer B is more important, it take
lots of time and operation.. overall if the move are chained ! canceling them all to
allow OpenERP to reaffect the sales to customer B take too much time.
● => A more important customer than another is a very common case in
real life. We need to handle this properly !
● If more than one product are in that case, it become the hell.
20/51
2.2.2.2: routing at reception
In this use case we will receive fresh tomatoes and frozen ice cream in one shipment, but
the different products will need to follow a different route through the warehouse.
Location Config:
● Input (docks)
● Freezer input
● Fresh input
● Stock Freezer
○ Freezer A
○ Freezer B
● Fresh
○ Fresh table A
○ Fresh table B
Steps:
● A purchase order will create an incoming shipment towards Input from Supplier
Confirmed: Supplier Input
● Then if there are products with different push rules, when the original moves will
propagate it will split in several pickings accordingly to the destination location.
● Thus, we will have the following routing:
Fresh Input Stock Fresh
● The last pushes eventually become:
Assigned: Freezer Input Freezer A
Assigned: Fresh Input Fresh Table A
(*) Put Away Strategy
21/51
It is also possible that the freezers and the fresh tables are close to each other and the
Freezer Input and the Fresh Input are the same (maybe even Input). Then the removal
strategies will split the stock moves instead of the push rules splitting the picking.
As a summary:
● Split of picking (and, thus, operations): push rule
● Split of lines but keep the same picking (in the same operation, by the same
worker): put away strategy
2.2.2.3: Supplier direct delivery (in MTO from SO) / Drop shipping
In order to resolve the dropshipping cases, we suggest to create, at the confirmation of the
SO, a procurement on the customer location instead of a procurement on output + stock
move from output to customer. The picking from output to customer will be managed by
the procurement instead of the SO (need toc reate a pull rule)=> we will remove a bunch
of code and simplify the whole process (we may need to remove some code from
stock_location and move it in stock (procurement that creates an internal move)
22/51
More over, the MTO/MTS selection field is not useful anymore on a sale order line. As an
example, take a “Pick → Pack → Ship” process; there is no interest to set the Ship
operation in MTS/MTO. This means we have to replace the MTS/MTO selection field on
the sale order line by a route selection. (MTO becomes an available route that impact the
Pick operations, downstream)
When doing a sale order, routes should come from:
● the warehouse (required to process Customers location), e.g.: Pick → Pack → Ship
● the sale order lines (optional), e.g.: MTO
Routes must be assigned to stock.move and propagated to procurement (using others
routes defined on pull rules.)
As this requires a lot of setup, the modules “stock” and “stock_location” must implement all
the default routes and pull rules so that the user just have to select an existing route when
doing a flow.
In batch picking, groups of orders are picked at the same time to minimize repeat visits to
the same product bin location. An order management system will arrange a group of
orders in the most efficient picking sequence and those orders are picked in the same time
(all P1 products are picked and 5 are placed in X while 10 are placed in Y, then the
operation is repeated for P2, P3, P4).
To implement batch picking:
24/51
● Use pull rules between Pick Zone and Stock
● So, pickings will remain the same than the sale order (this allows to prepare
pickings by packing or do pick and pack at the same time)
2.3.2.2. Wave Picking
In bigger warehouses, it may be more efficient to work in wave picking instead of batch
picking. In this method, the operations are grouped by products, not by order (pack). This
allow a more efficient management of load/volume constraint but involves also to rebuild
orders.
To implement this with our solution, you need to:
● define an automatic orderpoint (minimum 0, maximum 0) on the pick zone that
creates picking for each product. (in the stock zone) instead of a pull rule.
To
implement this, we need to be able to create orderpoints of categories of products
(child_of)
● This would generate lots of pickings with one line that will be grouped efficiently
with the wave algorithm
2.3.2.3 Trip assignation
Once the packs are done, we may use the waves to group together all the delivery orders
in the same area. This wave would reflect the places the carrier would have to do in a
single trip.
Once all packs have been done (or during the operation of doing the packs):
● You can create wave per trip (automatically or assign manually each pack to a trip
by setting the wave_id)
● Then, you can assign trips to Doors/Gateway by moving the wave to the right
location. We should implement a few operation in a wave:
○ validate all pickings at once
25/51
○ print the wave
○ pack all the wave in one packagin → this would allow to move all products
of the wave in one operation. (internal move) → don’t thnk we need this
● Steps
The warehouse manager gets overview of all delivery orders
Delivery A → France
Delivery B → Germany
Delivery C → Switzerland
Delivery D → Netherlands
The warehouse managers know that tomorrow transporter A will arrive with
cheapest tariffs to Germany and Switzerland
The day after transporter B will arrive specialized in France and the Netherlands
The warehouse managers knows they can all deliver in time. He will assign B and
C to the transport tomorrow of transporter A and A and D to the transport of
transporter D. So the wave_id becomes a transport.
Every transport will get a dock assigned
When the movement from Packing to Gates gets assigned, the PutAway strategy
has to check the Delivery Order to see to which gate it is assigned.
26/51
2.4 Quants
2.4.1 Concept Explained
The Quants is a new table that stores the current state of stock (per location). It is updated
each time a stock.move is set to done and has 3 main impacts:
● it allows optimization of computation (quantity available for example), because it
only contains information about the current stock (not the past or the future). The
volume is thus smaller and doesn’t grow with time.
● it will also be used in FIFO costing, as we need to match the incoming and
outgoing moves for a correct stock valuation.
● this table can also be used for the upstream/downstream traceability and the lot
management: this table will also contains the information about lots and, a list of
stock moves that explains the current stock level a record is depicting (it will
replace the 2 one2many ‘move_history_ids’ and ‘move_histoy_ids2’, currently used
to get the chained moves). This field is called history_ids later on the doc.
The following properties should be on the Quant
● lot #, many2one:
○ serial #
○ expiry date...
● cost price (in the currency of the company)
● quantity (of this lot)
● location_id (of this lot)
● pack_id (see later for packaging)
● reservation_move_id (ID of the move that assigned/reserved this quant)
● history_ids:
The following properties should be on the stock.move:
● quantity (total quantity to move)
● src location
● dest location
● quant_ids (inversed one2many: reservation_move_id)
27/51
Procurement Yes Yes Yes
Stock.quants Yes / /
This means:
● Consumables follows push and pull rules
● But there is no putaway/removal strategies on consumables
● No inventory valuation possible for consumables too
28/51
29/51
● 3 PCE Input, unit price 13€ (history_ids: ID2)
The stock valuation is simply 5x10€ + 3x13€.
If we do the following stock.move:
● ID3: 7 PCE, Input → Stock
We got the following Quants:
● 5 PCE Stock, unit price 10€ (history_ids: ID 1, ID3)
● 2 PCE Stock, unit price 13€ (history_ids: ID 2, ID3)
● 1 PCE Input, unit price 13€ (history_ids: ID2)
Let’s suppose i now move 6 products from stock → customer
The Quants table now looks like
● 5 PCE Customer, unit price 10€ (history_ids: ID 1, ID3, ID4), valuated as 5x10€
● 1 PCE Customer, unit price 13€ (history_ids: ID 2, ID3, ID4), valuated as 1x13€
● 1 PCE Stock, unit price 13€ (history_ids: ID 2, ID3)
● 1 PCE Input, unit price 13€ (history_ids: ID2)
Question:
HOW MANY PRODUCT DO I HAD ON THE 1st JANUARY with this !!? What was the real
value of the stock in location “stock” (for example for a product with a price that change
with the time (like gold for example)) + think about landed costs integration
=> SQL Query to compute the inventory at a specific date:
● select qty, cost, product_id, (select location_dest_id from stock.move m where
m.id=q.move_id and date_done<=DATE order by date_done limit 1) from quants;
○ + join on m2m history_ids
● + price historization
Currently, removal strategy works on stock.move, but they should be implemented at
stock.quant level.
A quant can be assigned to a move to do or not (reservation mechanism) with the
reservation_move_id field.
The removal strategy finds the quant amongst all quants in a specific location being not
reserved yet. It assign the quant to the move by setting the reservation_move_id.
31/51
The Quants table is now:
20 PCE customer (history_ids: ID1, ID2)
10 PCE customer (history_ids: ID2, ID3)
10 PCE customer (history_ids: ID2)
10 PCE output (history_ids: ID2)
● Finally, yet another 20 pieces arrive with ID4. The negative record in the Quants
table is updated and as it becomes 0 it is removed. We add the positive balance as
a new Quants record:
20 PCE customer (history_ids: ID1, ID2)
10 PCE customer (history_ids: ID2, ID3)
10 PCE customer (history_ids: ID2, ID4)
minus 10 PCE output (history_ids: ID2)
10 PCE output (history_ids: ID4)
In order to achieve the above use case, the system must be able to “reconcile” quants to
link a negative one with a positive (and, thus, generate accounting entries)
This reconciliation can happen automatically when the goods received later, pass in the
exact location of the negative quant. Depending on the PutAway rules e.g., it is possible
that the goods e.g. end up in the location next to the location of the negative quant e.g. bin
B instead of bin A.
In that case, we provide a menu (or a filter) that shows the negative quants. Then we can
tell the system that we used the box from bin B in bin A. The system will create a move
from bin B to bin A and as bin A has the negative quant, this will propagate the original
move in the history_ids in the same way as in the example above.
2.4.2.7 Impact on performance
This would speed up all operations like:
● quant selection (confirm → assign on stock move: removal strategies)
● quantities available (according to warehouse, location, …)
Because:
● Computations are made on products that are still in the warehouse (limited volume
of data, index on location_id), rather than all stock.move since the creation of the
company (explosion of data)
We can even speed up virtual stock computation because we base them on two limited
sets of records: “quants” +” move not done”
Inventory reports must be changed to use quants instead of stock.move. Same for
quantities on products or locations, they should be implemented using the quant table.
32/51
2.4.3 Separation of concepts
The clear separation of concepts allows an easier implementation and an easier
configuration of the whole system.
Object Impacting Concept Used For
33/51
eventually automatically create or split lots numbers.
On doit pouvoir enforcer qu’un serial number est créé et proposé automatiquement par
OpenERP (à la réception/ manufacturing unique).
Il faut une contrainte d’unicité pour certains produits, afin de gérer les traceabilités à la
pièce (case à cocher sur le produit + constraint sur les Quants)
2.6 Packings
Removal Strategies
Toute la complexité de la gestion des packs est dans le removal strategy (et éventuellment
dans les changements de quantité entre deux opérations chainées → moins c’est ok, mais
plus peut poser des problèmes)
L’algo doit ressembler à qqch du genre, implémenté dans la removal strategy:
● Prendre les packs du move chainée précédent s’il y en a
● S’il n’y en a pas, utiliser les stratégies (à définir) du genre: si j’ai besoin de 10
produits, je vais plutôt prendre une boite de 10 que 10 pièces isolées. On doit avoir
plusieurs stratégies par emplacements, ex: estce que j’accepte d’ouvrir une boite
lors de la mise en stock de marchandises reçues
L’assignation des stock.move doit se faire en masse (en tous cas par picking), et non pas
un par un car un pack peut contenir plusieurs produits différents.
34/51
Packing in stock.picking
During an operation (picking, packing, internal move, reception), we need to be able to:
● pack products in others handling units. (put products in boxes)
● move packs (a whole pallet)
● pack handling unites in others handling units (put boxes on pallets)
The same object (stock.picking) can be used for receptions, internal moves, picking,
packing, shipments, … So, we need one flexible interface that adapts to main needs.
We propose to split two concepts on the same picking:
● What should be done, the current product lines (stock.move)
○ 505 PCE Computer
○ 10 PCE Mouse
● What I do do, (the exact physical operation: moving boxes, packing products, …)
○ 5 Boxes (containing 100 computers)
○ 1 box (containing 10 mouse)
When the picking is validated, we do the difference between what have been done and
what should have been done and it generate optionally a backorder, in this scenario:
● 5 PCE Computer
This system would replace the current popup wizard with quantities processed (partial
picking wizard).
Exemple of such an interface: http://www.youtube.com/watch?v=QaflmApHX0k
In the package section, you can select products or handling units (e.g.boxes)
. When
35/51
a picking goes from confirmed to assigned, the removal strategies apply and OpenERP
proposes automatically the handling unit according to the required quantities. (and chained
moves. (a web module development) → it’s not packaging, it’s what you do (move
products, move boxes)
When we click on the “pack” button, it takes all products and boxes that are
selected and create a package in the bottom right. (need to add a checkbox on the left
of Laptop computers in the above mockup)
The package many2one (Pack/001) in the above mockup) can be empty.
A tooltip must be defined on the product line (e.x. 505 laptop computers). If you put your
mouse over, OpenEPR suggest appropriate packaging methods according to the
quantities of this product: “5 box X of 100, 1 box of 5”, “2 box Y of 200, 1 box of 100, ….”
The bottom one2many as a default value only if preceding moves are chained (e.g. ship of
a previously packed parcel). If no move is chained, the one2many is empty by default.
As in v7, location is:
● source for internal move & delivery orders
● destination for incoming shipments
The package (PACK/001) can be a new package (usually) or an existing one (moving
product in one existing palet) → this field should be a many2one (allowing select or create)
We need a print button to print a pack list on a selected pack.
To manage homogeneous package when packing operation (series of package), you just
click on (+) icon to do several packages of the same type . there will be a integer field to let
the user encode how much of the same package he wants.
We may add a “copy all” or “clear all” button that will copy ordered qty to processed qty.
OpenERP will automatically manage the creation of the stock.quant.pack object and it may
eventually move it into another stock.quant.pack (if you move a box and put it in a pallet)
The package one2many is filled automatically, with default value, by OpenERP at the
assignation of the picking. (proposition of packaging) only if they are chained moves
This system replaces the confirmation wizard with quantities as it does the same (compare
what should have been done (product lines) and what we did (packs) and create a back
order if necessary)
In the picking one2many, we may add a “Preferred Packing” field with the information that
comes from the sale order. (and the product)
36/51
Ideally, this UI should be like the POS:
● support for disconnected mode (you load a picking wave and you can work in local
storage)
● responsive design to work on small screens
This would allow to support major barcode readers without specific hardware interfaces.
Examples
37/51
● Top: filled with products from the order
● Bottom: Filled with packs from the picking (batch picking) if he did pack during the
picking operation
→ the user just has to validate (and may be pack differently)
Initial screen, wave picking:
● Top: filled with products from the order
● Bottom: empty (as it’s not a pull mto, but an orderpoint)
→ the user should record the packing
Use Case 4: Ship
Initial screen, batch picking:
● Top: filled with products from the order
● Bottom: Filled with packs from the packing
The user just has to validate.
Use Case 5: Partial Pick
Initial screen:
● Top: filled with products from the order
● Bottom: empty
The user starts to record what he does (products or boxes move) and the remaining
column changes. Then, he validates the whole picking and the backorder is created with
remaining products. (like current v7 implementation).
38/51
2.7.1 Basics
39/51
Another limitation is explained in the following example: let’s suppose i receive a product
that i configured with real time valuation, real costs for costing method and FIFO for the
removal strategy. This time, i purchased 10 pieces at 10€ the unit but i had a remaining
stock of 5 pieces at 8€ the unit. At the time of receiving the incoming shipment, i realize i
have an outgoing shipment for the same product planned, and i decide to make cross
docking to avoid useless stock movements. The outgoing products will be valuated at the
price of 10€ instead of 8€ as would have suggested the FIFO removal strategy.
40/51
locations. → this has impact of accounting entries and costing.
2.7.6 Implementation
The journal entries generation and price adjustment must be private methods on the
quants, not on the stock.move. We should move all methods on the quant object.
2.8 Multi-Company
41/51
calculation method. That way if you validate a stock move from another company, it
will create the valuations according to the methods and prices of the company of
the stock move.
The owner of the stock of an internal location is the company of the location. If the
owner is an external company, the type is not internal (and it’s address can be
specified on the location)
● vérifier que le mass import de records avec des champs property fonctionne => ce
qu’on veut avoir c’est produit | cost price in company A | cost price in company B.
→ It does not work; a simple solution would be to import several lists (one for each
company)
● on doit avoir que tous les champs sur la fiche produit sont dans la devise de la
compagnie MAIS on garde le comportement actuel pour le sale price parce que
c’est pas la problématique adressée ici
● vérifier le price_get a cause du changement en champ property et éventuellement
modifier la facon de gèrer le prix d’achat par défaut (ne plus baser cela par rapport
au cost price car c’est débile)
42/51
monday in the system => We should be able to put a date in the past)
○ permettre de setter la date done du move
● planned date on the picking must be computed accordingly to the picking policy
○ date la plus proche ou la plus éloignée selon le cas
● vues a revoir pour permettre d’encoder la scheduled date sur les pickings
● grouper les stock move dans les pickings de manière intelligente, pour pas avoir un
picking contenant des move avec 2 mois d’écart par exemple
● add the scheduled date on the PO line (computed as date planned on the PO +
lead time of the product)
The replenishment rule needs to be assigned to a product Category or to a product and for
a Stock Location or a warehouse (as in standard when a rule is set for a parent location,
the inventories taking into account in the replenishment calculation includes the children
locations*). A hierarchy has to be followed: if the replenishment rule is assigned at product
level, this one will be used if no rule is assigned; system will use the one of the product
category if existing. If not, no replenishment rule will be applied.
Date (frequency and start of policy applying) can be determined at category/class level
(and of course at product level).
Variable quantity calculation method can be selected at category/class level (and of
course at product level).
Fixed quantities have to be defined at product level on standard UoM.
The previous choices will imply one of the below policies:
Combined Fixed Date Variable Date
Combinedpolic
y
Fixed Quantity Automatic Supply Min/Max or Reorder point
Variable Order Cycle “Opportunist” Supply or
Quantity Threshold value
→ These should be an improvement of orderpoints, not a new concept. Eg for improving
order point:
● Quantity to Order: Fixed / Replenish Until Max
○ define a max
○ or define a fixed qty
● Cycle:
43/51
○ Every day (current behaviour) / Week / Month
○ Like the current features on recurring meeting: day/hour of week, day of
month, X weeks, …
● Based on:
○ Minimum Qty
○ Other for opportunist supply
Note that I am not sure that the Cycle should be implemented at the orderpoint
level. It
may be more efficient to implement cycle in the PO process (or procurement). → e.g. I
want to order to this supplier on mondays. (whatever if needs come from MTO,
procurements or orderpoints)
Safety stock in “absolute” quantity or on based period quantity should be set if needed.
2.12 KPI
To evaluate activities and measure “performance” of any Supply chain, indicators are
requested.
Indicators analyze needs to be quick and easy to be useful. The idea is then to provide a
tool to create a kind of dashboard with personalized indicators selection with appropriate
reference values optionally.
Example of basic KPIs:
● Cycle time of Purchase orders
● Supplier punctuality (Percentage of PO lines on time/late)
● Cycle time of Sales orders (average)
● Total stock value: value for all internal location, by location, by view…
● Value of quantity expired / loss
● Nb of references of non moving stocks,
● Volume of POs (Number of POs, Total number of PO’s line , Total amount of
POs (monthly/annual) ; Number of lines received
● Volume of Shipment (by destination, by transport mode, by month / annual.) ;
Number of lines shipped
If it’s ok for C2C, I propose that this analysis do not cover reporting and KPI. We should
better focus on the main flows. You should just verify that our solution fits your reporting
need.
Reports are an implementation effort, not an analysis effort.
44/51
received if we refused products during quality control, after the reception?
We should make the difference between:
● The purchase order is closed (reception has been made)
● The procurement is fulfilled (product arrived where I expected it, e.g. in the stock,
after the quality control)
In this regard, if you receive all the products you purchased but you refuse some after the
quality control: the purchase order is considered as received (you received everything) but
the procurement is not (products did not arrive in the stock). Depending on how you
handle this, you may trigger:
● return of products + request for refund
● return of products + reviewed expected invoice
● return of products + ask for new products
● scrap of products + …
So, a purchase order is marked as “received” when you received all the products (the first
operation), even if you decide to scrap, return or introduce a claim after.
In case of chained moves, the purchase order is “Received” when the first reception has
been done. In case of backorders, the purchase order is “Received” when the last
backorder has been closed (received or cancelled) If one reception is done, the PO is
closed. If all receptions are cancelled, the PO is cancelled.
If further operations (like quality control) requires that you send back products to your
supplier, it should be another request:
● new expected incoming shipment
● change in the expected invoice
We think the current workflow of the purchase order is correct in that regard.
But no other workflow should rely on the workflow of a purchase order to know if products
arrived or not. The procurement workflow should rely on the reception of the product
(stock.move) rather than the purchase order for stockable/consumable products.
The procurement should be changed in order to “listen” to the stock.move instead of the
purchase order
Modularity
The different features should be splitted across different modules:
● stock: Inventory Management (+ most basic operations) (including the stock
packing web UI)
● stock_location: Warehouse Management
● stock_picking_wave: Picking Waves
Feature Module
46/51
Push stock_location
Pull stock_location (basic pull rule in stock)
Put Away stock_location
Removal stock (simple strategies)
stock_location (advanced strategies)
Most advanced routing operations should be placed in the module stock_location
wherever it’s possible without bloating too much the code.
The idea is that a company that manages a warehouse without routes inside this
warehouse would use only stock and not stock_location. So, they do not need push/pull
rules, putaway strategies and removal strategies. (stock just include the basic removal
strategy on the product)
Removal strategy should be in the stock module because the mechanism of reservation of
quants is based on the removal strategy. More advanced removal strategies than FIFO
can be in the stock_location module.
Negative Quants
Negative quants are generated when the user forces the validation of a stock.move from a
location having no products (quants) available.
Negative stocks are a problem because:
● You can not do the accounting valuation
● You have to create a quant without having the right data about it (lot, cost, …)
In this situation, we create a negative quant in the source location that is the opposite than
the positive quant generated at the destination location. This negative quant should be
reconciled with a positive quant arriving in this location (having a cost, …) During the
reconciliation, the right data are set on the quant related to the negative one (costs, …)
So, we need an automatic reconciliation system to link negative quants with newly created
positive quants no yet assigned to another operation.
Identified Issues
Our solution does not handle:
47/51
● Reception of handling units (e.g. palets) without knowing the exact content and
filling the content afterwards. We chose not to support this case in this analysis to
keep things simple. This leaves two possible implementations: 1/ receive all
“expected” products according to the PO or delivery note and update numbers
afterwards. 2/ Record the detailed reception afterwards.
● Computation of the best route between two locations: we support several
possibilities for removal or putaway but not several routes between two locations.
(one has always priority on another one using sequences) It’s not covered by this
analysis as we think it’s better not to implement it for now on.
● A scheduler that proposes to move Bins instead of products/handling units. It’s
possible to move BINS (=locations) manually, but our scheduling tool will always
propose to move packs or products rather than BIN. We also have no transfer
order for BINs.
There are probably lots of others small needs that are not covered by this analysis. Our
goal is to propose a solution for solid foundations, not to cover all possible logistic scenarii.
If foundations are strong, it should not be complex to add more features in extra modules.
Misc points
1. MTS/MTO should be managed at the stock.move level
remove MTS/MTO from sale order lines, replace it by a route_id field
remove MTS/MTO from procurements (a procurement is always MTO)
put MTS/MTO on the stock.move
add route_id in procurement.group
add "sale", a fields.boolean on procurement in sale module (this
route is selectable in the sale.order)
The MTS/MTO selection field on the sale order line is replaced by a
route_id field on sale.order.line (with domain [('sale','=',True)])
This would allow to select "DropShipping" at the sale order line by
selecting "DropShipping" route.
We consider that all procurements are MTO.
For tasks, add a field.boolean on product.product "Create Task Automatically". The
procurement will use this field to know if it's a task or nothing.
The default on stock.move is MTS
48/51
2. procurements are created by MTO stock.move, not by pull rules
Create procurements based on stock.move as MTO (when the move is
confirmed). If a stock.move is MTS, no procurement is created.
A pull rule should not create a procurement on the source location of a
stock.move (> the procurement is automatically created by the
stock.move itself)
The scheduler should look to all confirmed stock.move and try to reserve
them. (to test further)
3. Merge trunkwmsimplementseducefp into trunkwmsimplementseduce
So that we have only one branch: trunkwmsimplementseducefp (did opposite)
4. Cleaning
[QDP] Remove file: stock/stock_fifo_lifo.py
Remove module stock_location_sale
5. Module sale
The "sale" module should create the procurement, not sale_stock
The sale_stock module should be removed to the minimum:
property handling
views (like open delivery orders)
6. Groups:
when a stock.move is confirmed, if no picking_id is associated;
find a confirmed picking when same source_destination and group_id
if no group_id or no picking exists: create picking
if the stock.move is MTO, create a procurement at the source location.
Create group when picking is created without group (picking confirm)
[JCO] 7. MRP
49/51
No need to create a stock.picking before the manufacturing order, the
removal strategy will do the job. Remove this extra step,
remove stock_auto_picking module.
8. Purchase
Merge the code of CSN that makes the difference between "Draft Purchase
Orders" and "Request for Quotation".
When a procurement have to buy something, it tries to add the line to an
existing purchase order that is still in "Draft Purchase" for the same
supplier.
[QDP] 9. Clean Stock.picking Invoicing
Remove all invoice_... stuff from stock module.
Just create one method in sale_stock allowing to create an invoice from
a stock.picking. > no more hooks.
[QDP] 10. Costing
Change costing method on product: average/standard/real costs
implement the stock valuation
11. do not link stock.move with sale order lines
beacause it's not needed, procurement group does the trick
50/51
51/51