[ADD] stock_account: stock valuation layer

This commit brings the model, views and compute method for the value and
the quantity valued. An ir rule prevents to read the value of another
company. Stat button are added on done picking to access the generated
layers.

Further commits will adapt one by one the cost method to actually use
the stock valuation layer when

As the goal is to move the valuation fields away from the stock move, we
set the necessary fields on the layer. Note the absence of `remaining_value`.

task-1875873
This commit is contained in:
Simon Lejeune
2019-06-09 14:11:36 +00:00
parent 7a27d52d71
commit 2c77efb05c
10 changed files with 171 additions and 0 deletions
+1
View File
@@ -31,6 +31,7 @@ Dashboard / Reports for Warehouse Management includes:
'views/res_config_settings_views.xml',
'data/product_data.xml',
'views/product_views.xml',
'views/stock_valuation_layer_views.xml',
],
'test': [
],
+2
View File
@@ -11,4 +11,6 @@ from . import stock_move
from . import stock_inventory
from . import stock_location
from . import stock_move_line
from . import stock_picking
from . import stock_valuation_layer
from . import res_config_settings
@@ -10,3 +10,5 @@ class AccountMove(models.Model):
_inherit = 'account.move'
stock_move_id = fields.Many2one('stock.move', string='Stock Move')
stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'account_move_id', string='Stock Valuation Layer')
+20
View File
@@ -60,6 +60,26 @@ class ProductProduct(models.Model):
stock_fifo_manual_move_ids = fields.Many2many(
'stock.move', compute='_compute_stock_value')
value_svl = fields.Float(compute='_compute_value_svl')
quantity_svl = fields.Float(compute='_compute_value_svl')
stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'product_id')
@api.depends('stock_valuation_layer_ids')
def _compute_value_svl(self):
"""Compute `value_svl` and `quantity_svl`."""
domain = [
('product_id', 'in', self.ids),
('company_id', '=', self.env.user.company_id.id)
]
if self.env.context.get('to_date'):
to_date = fields.Datetime.to_datetime(self.env.context['to_date'])
domain.append(('create_date', '<=', to_date))
groups = self.env['stock.valuation.layer'].read_group(domain, ['value:sum', 'quantity:sum'], ['product_id'])
for group in groups:
product = self.browse(group['product_id'][0])
product.value_svl = group['value']
product.quantity_svl = group['quantity']
@api.multi
def do_change_standard_price(self, new_price, account_id):
""" Changes the Standard Price of Product and creates an account move accordingly."""
@@ -20,6 +20,7 @@ class StockMove(models.Model):
remaining_qty = fields.Float(copy=False)
remaining_value = fields.Float(copy=False)
account_move_ids = fields.One2many('account.move', 'stock_move_id')
stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'stock_move_id')
@api.multi
def action_get_account_moves(self):
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class StockPicking(models.Model):
_inherit = 'stock.picking'
def action_view_stock_valuation_layers(self):
self.ensure_one()
domain = [('id', 'in', self.move_lines.stock_valuation_layer_ids.ids)]
action = self.env.ref('stock_account.stock_valuation_layer_action').read()[0]
return dict(action, domain=domain)
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class StockValuationLayer(models.Model):
"""Stock Valuation Layer"""
_name = 'stock.valuation.layer'
_description = 'Stock Valuation Layer'
_order = 'create_date, id'
_rec_name = 'product_id'
company_id = fields.Many2one('res.company', 'Company', readonly=True, required=True)
product_id = fields.Many2one('product.product', 'Product', readonly=True, required=True)
quantity = fields.Float('Quantity', digits=0, help='Quantity', readonly=True)
uom_id = fields.Many2one(related='product_id.uom_id', readonly=True, required=True)
currency_id = fields.Many2one('res.currency', 'Currency', related='company_id.currency_id', readonly=True, required=True)
unit_cost = fields.Monetary('Unit Value', readonly=True)
value = fields.Monetary('Total Value', readonly=True)
remaining_qty = fields.Float(digits=0, readonly=True)
description = fields.Char('Description', readonly=True)
stock_move_id = fields.Many2one('stock.move', 'Stock Move', readonly=True)
account_move_id = fields.Many2one('account.move', 'Journal Entry', readonly=True)
@@ -2,3 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_account_stock_manager,account.account stock manager,account.model_account_account,stock.group_stock_manager,1,0,0,0
access_stock_picking_invoicing_payments,stock.picking,stock.model_stock_picking,account.group_account_invoice,1,1,1,0
access_stock_move_invoicing_payments,stock.move,model_stock_move,account.group_account_invoice,1,1,1,0
access_stock_valuation_layer,access_stock_valuation_layer,model_stock_valuation_layer,stock.group_stock_manager,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_account_stock_manager account.account stock manager account.model_account_account stock.group_stock_manager 1 0 0 0
3 access_stock_picking_invoicing_payments stock.picking stock.model_stock_picking account.group_account_invoice 1 1 1 0
4 access_stock_move_invoicing_payments stock.move model_stock_move account.group_account_invoice 1 1 1 0
5 access_stock_valuation_layer access_stock_valuation_layer model_stock_valuation_layer stock.group_stock_manager 1 1 1 0
@@ -12,6 +12,13 @@
<field name="domain_force">['|',('company_id','=',False),('company_id', 'in', company_ids)]</field>
</record> -->
<record model="ir.rule" id="stock_valuation_layer_company_rule">
<field name="name">Stock Valuation Layer Multicompany</field>
<field name="model_id" search="[('model','=','stock.valuation.layer')]" model="ir.model"/>
<field name="global" eval="True"/>
<field name="domain_force">[('company_id','=',user.company_id.id)]</field>
</record>
</data>
</odoo>
@@ -0,0 +1,95 @@
<odoo>
<record id="stock_valuation_layer_form" model="ir.ui.view">
<field name="name">stock.valuation.layer.form</field>
<field name="model">stock.valuation.layer</field>
<field name="arch" type="xml">
<form edit="0" create="0">
<sheet>
<group>
<group>
<field name="create_date" string="Date" />
<field name="product_id" />
<field name="stock_move_id" attrs="{'invisible': [('stock_move_id', '=', False)]}" />
</group>
</group>
<notebook>
<page string="Valuation">
<group>
<field name="quantity" />
<field name="uom_id" groups="uom.group_uom" />
<field name="currency_id" invisible="1" />
<field name="unit_cost" />
<field name="value" />
<field name="remaining_qty" />
</group>
</page>
<page string="Other Info">
<group>
<field name="description" />
<field name="account_move_id" attrs="{'invisible': [('account_move_id', '=', False)]}" />
<field name="company_id" groups="base.group_multi_company" />
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="stock_valuation_layer_tree" model="ir.ui.view">
<field name="name">stock.valuation.layer.tree</field>
<field name="model">stock.valuation.layer</field>
<field name="arch" type="xml">
<tree default_order="create_date desc, id desc" create="0" import="0">
<field name="create_date" string="Date" />
<field name="product_id" />
<field name="quantity" />
<field name="uom_id" groups="uom.group_uom" />
<field name="currency_id" invisible="1" />
<field name="value" />
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
<record id="stock_valuation_layer_search" model="ir.ui.view">
<field name="name">stock.valuation.layer.tree</field>
<field name="model">stock.valuation.layer</field>
<field name="arch" type="xml">
<search string="Valuation Layer?">
<filter string="Product" name="group_by_product_id" context="{'group_by':'product_id'}"/>
</search>
</field>
</record>
<record id="stock_valuation_layer_action" model="ir.actions.act_window">
<field name="name">Stock Valuation</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">stock.valuation.layer</field>
<field name="view_mode">tree,form</field>
<field name="view_type">form</field>
<field name="view_id" ref="stock_valuation_layer_tree"/>
<field name="domain"></field>
<field name="context">{'search_default_group_by_product_id': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
There is no valuation layers. Valuation layers are created when some product moves should impact the valuation of the stock.
</p>
</field>
</record>
<record id="stock_valuation_layer_picking" model="ir.ui.view">
<field name="name">stock.valuation.layer.picking</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form" />
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button string="Valuation" type="object"
name="action_view_stock_valuation_layers"
class="oe_stat_button" icon="fa-dollar" groups="stock.group_stock_manager"
attrs="{'invisible': [('state', 'not in', ['done'])]}" />
</xpath>
</field>
</record>
</odoo>