[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:
@@ -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': [
|
||||
],
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user