Odoo Help


This community is for beginners and experts willing to share their Odoo knowledge. It's not a forum to discuss ideas, but a knowledge base of questions and their answers.


What is the proper way of using UoM and UoS in Stock Move

on 5/22/15, 4:03 AM 1,110 views

I believe the question is related to one unanswered question: https://www.odoo.com/forum/help-1/question/stock-move-problem-82980

Anyway, let me described the situation that I'm facing:

An order (be it Sales Order or Purchase Order) is created for Product A for a quantity of 1 ton.  It is set for Invoicing after Stock Picking is created (Based on incoming shipments for Purchase Order and On Delivery Order for Sales Order).  Product A has a default UoM of kg and UoS is not set and UoS Coeff = 1 (default).

Now, within the Stock Picking created, since Product A is received in bags of 40 kgs, the Quantity and UoM received is changed to 25 bags.  When the quantity is changed, it will calculate UoS Quantity, however it does not update it according to the UoM change. The code is (addons/stock/stock.py:onchange_quantity):

if product_uos and product_uom and (product_uom != product_uos): 
result['product_uos_qty'] = product_qty * uos_coeff['uos_coeff']
result['product_uos_qty'] = product_qty

I see the same code is still used in v8.0

So, in result product_uos_qty will be 25 but the UoS is not changed.  I believe uos_coeff is meant to be the coefficient for the Product's default UoM.  I can't find (and from the view it is also not set) the onchange for UoM, but regardless whether there is on change for UoM, the change of UoM is not catered for in the above code.

Come Invoice creation, the code is as follows (addons/stock/stock.py:_prepare_invoice_line):

uos_id = move_line.product_uos and move_line.product_uos.id or False
if not uos_id and invoice_vals['type'] in ('out_invoice', 'out_refund'):
uos_id = move_line.product_uom.id

return {
'name': name,
'origin': origin,
'invoice_id': invoice_id,
'uos_id': uos_id,
'product_id': move_line.product_id.id,
'account_id': account_id,
'price_unit': self._get_price_unit_invoice(cr, uid, move_line, invoice_vals['type']),
'discount': self._get_discount_invoice(cr, uid, move_line),
'quantity': move_line.product_uos_qty or move_line.product_qty,
'invoice_line_tax_id': [(6, 0, self._get_taxes_invoice(cr, uid, move_line, invoice_vals['type']))],
'account_analytic_id': self._get_account_analytic_invoice(cr, uid, picking, move_line),
So, the Invoice will take the move_line.product_uos_qty (which is now 25) AND uos_id.  The uos_id is filled by either Sale Order (addons/sale_stock/sale_stock.py:_prepare_order_line_move) with (line.product_uos and line.product_uos.id) or line.product_uom.id or Purchase Order (addons/purchase/purchase.py:_prepare_order_line_move) with order_line.product_uom.id.  Since the Product's UoS is empty both are effectively filled with Product's default UoM.

Thus, the change of UoM is not factored in and the Invoice ends up to be 25 times of it's supposed value.

The code for v8.0 is similar.  The _prepare_invoice_line logic has been moved to addons/stock_account/stock.py:_get_invoice_line_vals.

Moving further, here is the code that determines the value used for Stock Valuation Journal (addons/stock/stock.py_get_reference_accounting_values_for_valuation, comments removed for clarity):

default_uom = move.product_id.uom_id.id
qty = product_uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, default_uom)

if move.location_dest_id.usage != 'internal' and move.product_id.cost_method == 'average':
reference_amount = qty * move.product_id.standard_price
elif move.product_id.cost_method == 'average' and move.price_unit:
reference_amount = qty * move.price_unit
reference_currency_id = move.price_currency_id.id or reference_currency_id
if context is None:
context = {}
currency_ctx = dict(context, currency_id = move.company_id.currency_id.id)
amount_unit = move.product_id.price_get('standard_price', context=currency_ctx)[move.product_id.id]
reference_amount = amount_unit * qty

reference_amount will be used as debit/credit.  So, qty variable is in the Product's default UoM.  If Product A's Costing Method (cost_method) is 'average' (Average Price), it will calculate reference_amount = qty * move.price_unit.  The move's price_unit is based set as product_id.standard_price in Sale Order (addons/sale_stock/sale_stock.py:_prepare_order_line_move) and order_line.price_unit in Company's currency (addons/purchase/purchase.py:_prepare_order_line_move).  In Sale Order's case the move.price_unit will be per Product's default UoM whereas in Purchase Order it will be per Purchase Order Line's UoM.

Since qty is in Default UoM, the valuation for Purchase Order moves (which is using ton) will be 1000 times of it's supposed value.

From the above, I'm in the impression that the UoM of Stock Move should not be altered in any way during processing and Purchase should be made in the default UoM.  Am I missing something?  Is there something that I've done incorrectly?

Thank you for your time.

Just listing Github bug that may be related to this: https://github.com/odoo/odoo/issues/3569 https://github.com/odoo/odoo/issues/3472 (closed, but creates another bug) https://github.com/odoo/odoo/issues/1840 https://github.com/odoo/odoo/issues/304

on 6/25/15, 7:09 AM

Github issue related to the Valuation entry: https://github.com/odoo/odoo/issues/5926

on 6/25/15, 7:18 AM

Your Answer

Please try to give a substantial answer. If you wanted to comment on the question or answer, just use the commenting tool. Please remember that you can always revise your answers - no need to answer the same question twice. Also, please don't forget to vote - it really helps to select the best questions and answers!

About This Community

This community is for professionals and enthusiasts of our products and services. Read Guidelines

Question tools

1 follower(s)


Asked: 5/22/15, 4:03 AM
Seen: 1110 times
Last updated: 8/4/16, 9:20 AM