mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[ADD] stock_inventory_revaluation
This commit is contained in:
committed by
Jordi Ballester Alomar
parent
ddbd5aa61e
commit
da2613d4a2
85
stock_inventory_revaluation/README.rst
Normal file
85
stock_inventory_revaluation/README.rst
Normal file
@@ -0,0 +1,85 @@
|
||||
.. image:: https://img.shields.io/badge/license-AGPLv3-blue.svg
|
||||
:target: https://www.gnu.org/licenses/agpl.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
===================================
|
||||
Stock Account Inventory Revaluation
|
||||
===================================
|
||||
|
||||
If your company runs a perpetual inventory system, you may need to perform
|
||||
inventory revaluation.
|
||||
|
||||
You can re-valuate inventory values by:
|
||||
|
||||
* Changing the price for a specific product. The inventory price is changed
|
||||
and inventory value is recalculated according to the new price. In case of
|
||||
real price, you can select which quants you want to change the price on.
|
||||
|
||||
* Changing the value of the inventory. The quantity of inventory remains
|
||||
unchanged, resulting in a change in the price.
|
||||
|
||||
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
|
||||
* Go to *Inventory / Configuration / Products / Product Categories* and
|
||||
define, for each category, a Valuation Increase Account and a Valuation
|
||||
Decrease Account. These accounts will be used as contra-accounts to the
|
||||
Stock Valuation Account during the inventory re-valuation.
|
||||
|
||||
* Users willing to access to the Inventory Revaluation menu should be
|
||||
members of the group "Manage Inventory Valuation and Costing Methods".
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
* Go to *Inventory / Inventory Control / Inventory Revaluation / Products*
|
||||
to create a new Inventory Revaluation.
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/154/8.0
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues
|
||||
<https://github.com/OCA/stock_account_inventory_revaluation/issues>`_. In
|
||||
case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and
|
||||
welcomed `feedback <https://github.com/OCA/154/issues/new?body=module:%20
|
||||
stock_account_inventory_revaluation%0Aversion:%20
|
||||
8.0%0A%0A**Steps%20to%20reproduce**%0A-%20..
|
||||
.%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Eficent Business and IT Consulting Services S.L. <contact@eficent.com>
|
||||
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: http://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
To contribute to this module, please visit http://odoo-community.org.
|
||||
6
stock_inventory_revaluation/__init__.py
Normal file
6
stock_inventory_revaluation/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from . import models
|
||||
from . import wizards
|
||||
26
stock_inventory_revaluation/__openerp__.py
Normal file
26
stock_inventory_revaluation/__openerp__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
"name": "Stock Inventory Revaluation",
|
||||
"summary": "Introduces inventory revaluation as single point to change "
|
||||
"the valuation of products.",
|
||||
"version": "8.0.1.0.0",
|
||||
"author": "Eficent Business and IT Consulting Services S.L., "
|
||||
"Odoo Community Association (OCA)",
|
||||
"website": "http://www.eficent.com",
|
||||
"category": "Warehouse",
|
||||
"depends": ["stock_account"],
|
||||
"license": "AGPL-3",
|
||||
"data": [
|
||||
"wizards/stock_inventory_revaluation_get_quants_view.xml",
|
||||
"security/stock_inventory_revaluation_security.xml",
|
||||
"security/ir.model.access.csv",
|
||||
"views/stock_inventory_revaluation_view.xml",
|
||||
"views/product_view.xml",
|
||||
"data/stock_inventory_revaluation_data.xml",
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="sequence_stock_inventory_revaluation_type"
|
||||
model="ir.sequence.type">
|
||||
<field name="name">Stock Inventory Revaluation</field>
|
||||
<field name="code">stock.inventory.revaluation</field>
|
||||
</record>
|
||||
|
||||
<record id="sequence_stock_inventory_revaluation" model="ir.sequence">
|
||||
<field name="name">Stock Inventory Revaluation</field>
|
||||
<field name="code">stock.inventory.revaluation</field>
|
||||
<field name="prefix">IR/</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
7
stock_inventory_revaluation/models/__init__.py
Normal file
7
stock_inventory_revaluation/models/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import product
|
||||
from . import stock_inventory_revaluation
|
||||
25
stock_inventory_revaluation/models/product.py
Normal file
25
stock_inventory_revaluation/models/product.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from openerp import fields, models
|
||||
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
|
||||
_inherit = 'product.category'
|
||||
|
||||
property_inventory_revaluation_increase_account_categ = fields.Many2one(
|
||||
'account.account', string='Valuation Increase Account',
|
||||
company_dependent=True,
|
||||
help="Define the G/L accounts to be used as the balancing account in "
|
||||
"the transaction created by the revaluation. The G/L Increase "
|
||||
"Account is used when the inventory value is increased due to "
|
||||
"the revaluation.")
|
||||
|
||||
property_inventory_revaluation_decrease_account_categ = fields.Many2one(
|
||||
'account.account', string='Valuation Decrease Account',
|
||||
company_dependent=True,
|
||||
help="Define the G/L accounts to be used as the balancing account in "
|
||||
"the transaction created by the revaluation. The G/L Decrease "
|
||||
"Account is used when the inventory value is decreased.")
|
||||
@@ -0,0 +1,450 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from openerp import api, fields, models, _
|
||||
import openerp.addons.decimal_precision as dp
|
||||
import time
|
||||
from openerp.exceptions import Warning as UserError
|
||||
|
||||
_STATES = [
|
||||
('draft', 'Draft'),
|
||||
('posted', 'Posted'),
|
||||
('cancel', 'Cancelled')]
|
||||
|
||||
|
||||
class StockInventoryRevaluation(models.Model):
|
||||
|
||||
_name = 'stock.inventory.revaluation'
|
||||
_description = 'Inventory revaluation'
|
||||
|
||||
@api.model
|
||||
def _default_journal(self):
|
||||
res = self.env['account.journal'].search([('type', '=', 'general')])
|
||||
return res and res[0] or False
|
||||
|
||||
name = fields.Char('Reference',
|
||||
help="Reference for the journal entry",
|
||||
readonly=True,
|
||||
required=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
copy=False,
|
||||
default='/')
|
||||
|
||||
revaluation_type = fields.Selection(
|
||||
[('price_change', 'Price Change'),
|
||||
('inventory_value', 'Inventory Debit/Credit')],
|
||||
string="Revaluation Type",
|
||||
readonly=True, required=True,
|
||||
default='price_change',
|
||||
help="'Price Change': You can re-valuate inventory values by Changing "
|
||||
"the price for a specific product. The inventory price is "
|
||||
"changed and inventory value is recalculated according to the "
|
||||
"new price.\n "
|
||||
"'Inventory Debit/Credit': Changing the value of the inventory. "
|
||||
"The quantity of inventory remains unchanged, resulting in a "
|
||||
"change in the price",
|
||||
states={'draft': [('readonly', False)]})
|
||||
|
||||
remarks = fields.Text('Remarks',
|
||||
help="Displays by default Inventory Revaluation. "
|
||||
"This text is copied to the journal entry.",
|
||||
readonly=True,
|
||||
default='Inventory Revaluation',
|
||||
states={'draft': [('readonly', False)]})
|
||||
|
||||
state = fields.Selection(selection=_STATES,
|
||||
string='Status',
|
||||
readonly=True,
|
||||
required=True,
|
||||
default='draft',
|
||||
states={'draft': [('readonly', False)]})
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company', string='Company', readonly=True,
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'stock.inventory.revaluation'),
|
||||
states={'draft': [('readonly', False)]})
|
||||
|
||||
document_date = fields.Date(
|
||||
'Creation date', required=True, readonly=True,
|
||||
default=lambda self: fields.Date.context_today(self),
|
||||
states={'draft': [('readonly', False)]})
|
||||
|
||||
journal_id = fields.Many2one('account.journal', 'Journal',
|
||||
default=_default_journal,
|
||||
readonly=True,
|
||||
states={'draft': [('readonly', False)]})
|
||||
|
||||
line_ids = fields.One2many('stock.inventory.revaluation.line',
|
||||
'revaluation_id',
|
||||
string='Revaluation lines',
|
||||
readonly=False,
|
||||
states={'posted': [('readonly', True)]})
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
sequence_obj = self.env['ir.sequence']
|
||||
if values.get('name', '/') == '/':
|
||||
values['name'] = sequence_obj.get('stock.inventory.revaluation')
|
||||
return super(StockInventoryRevaluation, self).create(values)
|
||||
|
||||
@api.one
|
||||
def post(self):
|
||||
for line in self.line_ids:
|
||||
if line.product_template_id.valuation != 'real_time':
|
||||
continue
|
||||
line.post()
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def button_post(self):
|
||||
self.post()
|
||||
self.write({'state': 'posted'})
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def button_draft(self):
|
||||
self.write({'state': 'draft'})
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def button_cancel(self):
|
||||
moves = self.env['account.move']
|
||||
for line in self.line_ids:
|
||||
if line.move_id:
|
||||
moves += line.move_id
|
||||
for line_quant in line.line_quant_ids:
|
||||
if line_quant.move_id:
|
||||
moves += line_quant.move_id
|
||||
line_quant.quant_id.write({'cost': line_quant.old_cost})
|
||||
if moves:
|
||||
# second, invalidate the move(s)
|
||||
moves.button_cancel()
|
||||
# delete the move this revaluation was pointing to
|
||||
# Note that the corresponding move_lines and move_reconciles
|
||||
# will be automatically deleted too
|
||||
moves.unlink()
|
||||
self.write({'state': 'cancel'})
|
||||
return True
|
||||
|
||||
|
||||
class StockInventoryRevaluationLine(models.Model):
|
||||
|
||||
_name = 'stock.inventory.revaluation.line'
|
||||
_description = 'Inventory revaluation line'
|
||||
|
||||
@api.one
|
||||
def _get_product_template_qty(self):
|
||||
self.qty_available = 0
|
||||
for prod_variant in self.product_template_id.product_variant_ids:
|
||||
self.qty_available += prod_variant.qty_available
|
||||
|
||||
@api.one
|
||||
def _calc_product_template_value(self):
|
||||
qty_available = 0
|
||||
current_value = 0.0
|
||||
quant_obj = self.env['stock.quant']
|
||||
for prod_variant in self.product_template_id.product_variant_ids:
|
||||
qty_available += prod_variant.qty_available
|
||||
if self.product_template_id.cost_method == 'real':
|
||||
quants = quant_obj.search([('product_id', '=',
|
||||
prod_variant.id),
|
||||
('location_id.usage', '=',
|
||||
'internal')])
|
||||
for quant in quants:
|
||||
current_value += quant.cost
|
||||
else:
|
||||
current_value = \
|
||||
self.product_template_id.standard_price * qty_available
|
||||
self.current_value = current_value
|
||||
|
||||
@api.one
|
||||
@api.depends("product_template_id", "product_template_id.standard_price")
|
||||
def _calc_current_cost(self):
|
||||
self.current_cost = self.product_template_id.standard_price
|
||||
|
||||
revaluation_id = fields.Many2one('stock.inventory.revaluation',
|
||||
'Stock Inventory Revaluation',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
|
||||
state = fields.Selection(selection=_STATES,
|
||||
string='UoM', readonly=True,
|
||||
related="revaluation_id.state")
|
||||
|
||||
product_template_id = fields.Many2one('product.template', 'Product',
|
||||
required=True,
|
||||
domain=[('type', '=', 'product')])
|
||||
|
||||
cost_method = fields.Selection(string="Cost Method", readonly=True,
|
||||
related='product_template_id.cost_method')
|
||||
|
||||
uom_id = fields.Many2one('product.uom', 'UoM', readonly=True,
|
||||
related="product_template_id.uom_id")
|
||||
|
||||
old_cost = fields.Float('Old cost',
|
||||
help='Displays the previous cost of the '
|
||||
'product.',
|
||||
digits=dp.get_precision('Product Price'),
|
||||
readonly=True)
|
||||
|
||||
current_cost = fields.Float('Current cost',
|
||||
help='Displays the current cost of the '
|
||||
'product.',
|
||||
digits=dp.get_precision('Product Price'),
|
||||
compute="_calc_current_cost",
|
||||
readonly=True)
|
||||
|
||||
new_cost = fields.Float('New cost',
|
||||
help="Enter the new cost you wish to assign to "
|
||||
"the product. Relevant only when the "
|
||||
"selected revaluation type is Price Change.",
|
||||
digits=dp.get_precision('Product Price'))
|
||||
|
||||
current_value = fields.Float('Current value',
|
||||
help='Displays the current value of the '
|
||||
'product.',
|
||||
digits=dp.get_precision('Account'),
|
||||
compute="_calc_product_template_value",
|
||||
readonly=True)
|
||||
|
||||
old_value = fields.Float('Old value',
|
||||
help='Displays the current value of the product.',
|
||||
digits=dp.get_precision('Account'),
|
||||
readonly=True)
|
||||
|
||||
new_value = fields.Float('Credit/Debit amount',
|
||||
help="Enter the amount you wish to credit or "
|
||||
"debit from the current inventory value of "
|
||||
"the item. Enter credit as a negative value."
|
||||
"Relevant only if the selected revaluation "
|
||||
"type is Inventory Credit/Debit.",
|
||||
digits=dp.get_precision('Account'))
|
||||
|
||||
qty_available = fields.Float(
|
||||
'Quantity On Hand', compute='_get_product_template_qty',
|
||||
digits_compute=dp.get_precision('Product Unit of Measure'))
|
||||
|
||||
increase_account_id = fields.Many2one(
|
||||
'account.account', 'Increase Account',
|
||||
help="Define the G/L accounts to be used as the balancing account in "
|
||||
"the transaction created by the revaluation. The Increase "
|
||||
"Account is used when the inventory value is increased due to "
|
||||
"the revaluation.")
|
||||
|
||||
decrease_account_id = fields.Many2one(
|
||||
'account.account', 'Decrease Account',
|
||||
help="Define the G/L accounts to be used as the balancing account in "
|
||||
"the transaction created by the revaluation. The Decrease "
|
||||
"Account is used when the inventory value is decreased.")
|
||||
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company', string='Company', readonly=True,
|
||||
related="revaluation_id.company_id")
|
||||
|
||||
move_id = fields.Many2one('account.move', 'Account move', readonly=True)
|
||||
|
||||
revaluation_type = fields.Selection(
|
||||
string="Revaluation Type", readonly=True,
|
||||
related='revaluation_id.revaluation_type',
|
||||
default='price_change')
|
||||
|
||||
line_quant_ids = fields.One2many('stock.inventory.revaluation.line.quant',
|
||||
'line_id',
|
||||
string='Revaluation line quants')
|
||||
|
||||
_sql_constraints = [
|
||||
('inv_valu_line_prod_temp_uniq',
|
||||
'unique (revaluation_id, product_template_id)',
|
||||
_('Cannot enter the same product multiple times in the same '
|
||||
'inventory valuation!'))]
|
||||
|
||||
@api.one
|
||||
@api.constrains('product_template_id', 'company_id')
|
||||
def _check_is_stockable(self):
|
||||
if self.product_template_id.type != 'product':
|
||||
raise UserError(_('Configuration error!\nThe product must be '
|
||||
'stockable.'))
|
||||
|
||||
@api.one
|
||||
@api.onchange("product_template_id")
|
||||
def _onchange_product_template_id(self):
|
||||
if self.product_template_id:
|
||||
self.increase_account_id = self.product_template_id.categ_id and \
|
||||
self.product_template_id.categ_id.\
|
||||
property_inventory_revaluation_increase_account_categ
|
||||
self.decrease_account_id = self.product_template_id.categ_id and \
|
||||
self.product_template_id.categ_id.\
|
||||
property_inventory_revaluation_decrease_account_categ
|
||||
self.revaluation_type = self.revaluation_id.revaluation_type
|
||||
|
||||
@api.model
|
||||
def _prepare_move_data(self, date_move):
|
||||
|
||||
period = self.env['account.period'].find(date_move)[0]
|
||||
|
||||
return {
|
||||
'narration': self.revaluation_id.remarks,
|
||||
'date': date_move,
|
||||
'ref': self.revaluation_id.name,
|
||||
'journal_id': self.revaluation_id.journal_id.id,
|
||||
'period_id': period.id,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _prepare_debit_move_line_data(self, amount, account_id, prod_id):
|
||||
return {
|
||||
'name': self.revaluation_id.name,
|
||||
'date': self.move_id.date,
|
||||
'product_id': prod_id,
|
||||
'account_id': account_id,
|
||||
'move_id': self.move_id.id,
|
||||
'debit': amount
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _prepare_credit_move_line_data(self, amount, account_id, prod_id):
|
||||
return {
|
||||
'name': self.revaluation_id.name,
|
||||
'date': self.move_id.date,
|
||||
'product_id': prod_id,
|
||||
'account_id': account_id,
|
||||
'move_id': self.move_id.id,
|
||||
'credit': amount
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _create_accounting_entry(self, amount_diff):
|
||||
timenow = time.strftime('%Y-%m-%d')
|
||||
move_data = self._prepare_move_data(timenow)
|
||||
datas = self.env['product.template'].get_product_accounts(
|
||||
self.product_template_id.id)
|
||||
self.move_id = self.env['account.move'].create(move_data).id
|
||||
move_line_obj = self.env['account.move.line']
|
||||
|
||||
if not self.decrease_account_id or not self.increase_account_id:
|
||||
raise UserError(_("Please add a Increase Account and "
|
||||
"a Decrease Account."))
|
||||
|
||||
for prod_variant in self.product_template_id.product_variant_ids:
|
||||
qty = prod_variant.qty_available
|
||||
if qty:
|
||||
if amount_diff > 0:
|
||||
debit_account_id = self.decrease_account_id.id
|
||||
credit_account_id = \
|
||||
datas['property_stock_valuation_account_id']
|
||||
else:
|
||||
debit_account_id = \
|
||||
datas['property_stock_valuation_account_id']
|
||||
credit_account_id = self.increase_account_id.id
|
||||
move_line_data = self._prepare_debit_move_line_data(
|
||||
abs(amount_diff), debit_account_id, prod_variant.id)
|
||||
move_line_obj.create(move_line_data)
|
||||
move_line_data = self._prepare_credit_move_line_data(
|
||||
abs(amount_diff), credit_account_id, prod_variant.id)
|
||||
move_line_obj.create(move_line_data)
|
||||
if self.move_id.journal_id.entry_posted:
|
||||
self.move_id.post()
|
||||
|
||||
@api.one
|
||||
def post(self):
|
||||
|
||||
amount_diff = 0.0
|
||||
if self.product_template_id.cost_method == 'real':
|
||||
for line_quant in self.line_quant_ids:
|
||||
amount_diff += line_quant.get_total_value()
|
||||
line_quant.write_new_cost()
|
||||
if amount_diff == 0.0:
|
||||
return True
|
||||
else:
|
||||
if self.product_template_id.cost_method in ['standard', 'average']:
|
||||
|
||||
if self.revaluation_id.revaluation_type == 'price_change':
|
||||
diff = self.current_cost - self.new_cost
|
||||
amount_diff = self.qty_available * diff
|
||||
else:
|
||||
amount_diff = self.current_value - self.new_value
|
||||
if self.new_value < 0:
|
||||
raise UserError(_("The new value for product %s "
|
||||
"cannot be negative"
|
||||
% self.product_template_id.name))
|
||||
if self.qty_available <= 0.0:
|
||||
raise UserError(
|
||||
_("Cannot do an inventory value change if the "
|
||||
"quantity available for product %s "
|
||||
"is 0 or negative" %
|
||||
self.product_template_id.name))
|
||||
|
||||
if self.revaluation_id.revaluation_type == 'price_change':
|
||||
self.old_cost = self.current_cost
|
||||
self.product_template_id.write({'standard_price':
|
||||
self.new_cost})
|
||||
else:
|
||||
self.old_cost = self.current_cost
|
||||
self.old_value = self.current_value
|
||||
value_diff = self.current_value - self.new_value
|
||||
new_cost = value_diff / self.qty_available
|
||||
self.product_template_id.write({'standard_price':
|
||||
new_cost})
|
||||
|
||||
if self.product_template_id.valuation == 'real_time':
|
||||
self._create_accounting_entry(amount_diff)
|
||||
|
||||
|
||||
class StockInventoryRevaluationLineQuant(models.Model):
|
||||
|
||||
_name = 'stock.inventory.revaluation.line.quant'
|
||||
_description = 'Inventory revaluation line quant'
|
||||
|
||||
line_id = fields.Many2one('stock.inventory.revaluation.line',
|
||||
'Revaluation Line', required=True,
|
||||
readonly=True)
|
||||
|
||||
quant_id = fields.Many2one('stock.quant', 'Quant', required=True,
|
||||
readonly=True,
|
||||
domain=[('product_id.type', '=', 'product')])
|
||||
|
||||
product_id = fields.Many2one('product.product', 'Product',
|
||||
readonly=True,
|
||||
related="quant_id.product_id")
|
||||
|
||||
location_id = fields.Many2one('stock.location', 'Location',
|
||||
readonly=True,
|
||||
related="quant_id.location_id")
|
||||
|
||||
qty = fields.Float('Quantity', readonly=True,
|
||||
related="quant_id.qty")
|
||||
|
||||
in_date = fields.Datetime('Incoming Date', readonly=True,
|
||||
related="quant_id.in_date")
|
||||
|
||||
current_cost = fields.Float('Current Cost',
|
||||
readonly=True,
|
||||
related="quant_id.cost")
|
||||
|
||||
old_cost = fields.Float('Previous cost',
|
||||
help='Shows the previous cost of the quant',
|
||||
readonly=True)
|
||||
|
||||
new_cost = fields.Float('New Cost',
|
||||
help="Enter the new cost you wish to assign to "
|
||||
"the Quant. Relevant only when the "
|
||||
"selected revaluation type is Price Change.",
|
||||
digits=dp.get_precision('Product Price'),
|
||||
copy=False)
|
||||
|
||||
def get_total_value(self):
|
||||
amount_diff = 0.0
|
||||
if self.product_id.product_tmpl_id.cost_method == 'real':
|
||||
if self.line_id.revaluation_id.revaluation_type != 'price_change':
|
||||
raise UserError(_("You can only post quant cost changes."))
|
||||
else:
|
||||
diff = self.current_cost - self.new_cost
|
||||
amount_diff = self.qty * diff
|
||||
return amount_diff
|
||||
|
||||
def write_new_cost(self):
|
||||
self.old_cost = self.current_cost
|
||||
self.quant_id.write({'cost': self.new_cost})
|
||||
return True
|
||||
4
stock_inventory_revaluation/security/ir.model.access.csv
Normal file
4
stock_inventory_revaluation/security/ir.model.access.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_inventory_revaluation,stock.inventory.revaluation,model_stock_inventory_revaluation,stock_account.group_inventory_valuation,1,1,1,1
|
||||
access_stock_inventory_revaluation_line,stock.inventory.revaluation.line,model_stock_inventory_revaluation_line,stock_account.group_inventory_valuation,1,1,1,1
|
||||
access_stock_inventory_revaluation_line_quant,stock.inventory.revaluation.line.quant,model_stock_inventory_revaluation_line_quant,stock_account.group_inventory_valuation,1,1,1,1
|
||||
|
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record model="ir.rule" id="stock_inventory_revaluation_comp_rule">
|
||||
<field name="name">Stock Inventory Revaluation multi-company</field>
|
||||
<field name="model_id" ref="model_stock_inventory_revaluation"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('company_id','=',False),
|
||||
('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="stock_inventory_revaluation_line_comp_rule">
|
||||
<field name="name">Stock Inventory Revaluation line multi-company</field>
|
||||
<field name="model_id" ref="model_stock_inventory_revaluation_line"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('company_id','=',False),
|
||||
('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
BIN
stock_inventory_revaluation/static/description/icon.png
Normal file
BIN
stock_inventory_revaluation/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
6
stock_inventory_revaluation/tests/__init__.py
Normal file
6
stock_inventory_revaluation/tests/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import test_stock_inventory_revaluation
|
||||
@@ -0,0 +1,240 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp.tests.common import TransactionCase
|
||||
from datetime import datetime
|
||||
from datetime import date, timedelta
|
||||
|
||||
|
||||
class TestStockInventoryRevaluation(TransactionCase):
|
||||
"""Test that the Inventory is Revaluated when the
|
||||
inventory price for any product is changed."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestStockInventoryRevaluation, self).setUp()
|
||||
# Get required Model
|
||||
self.product_model = self.env['product.product']
|
||||
self.product_ctg_model = self.env['product.category']
|
||||
self.reval_model = self.env['stock.inventory.revaluation']
|
||||
self.reval_line_model = self.env['stock.inventory.revaluation.line']
|
||||
self.account_model = self.env['account.account']
|
||||
self.acc_type_model = self.env['account.account.type']
|
||||
self.reval_line_quant_model = self.\
|
||||
env['stock.inventory.revaluation.line.quant']
|
||||
self.get_quant_model = self.\
|
||||
env['stock.inventory.revaluation.line.get.quant']
|
||||
self.stock_change_model = self.env['stock.change.product.qty']
|
||||
self.stock_lot_model = self.env['stock.production.lot']
|
||||
self.stock_location_model = self.env['stock.location']
|
||||
# Get required Model data
|
||||
self.fixed_account = self.env.ref('account.xfa')
|
||||
self.purchased_stock = self.env.ref('account.stk')
|
||||
self.debtors_account = self.env.ref('account.a_recv')
|
||||
self.cash_account = self.env.ref('account.cash')
|
||||
self.product_uom = self.env.ref('product.product_uom_unit')
|
||||
self.journal = self.env.ref('account.miscellaneous_journal')
|
||||
self.company = self.env.ref('base.main_company')
|
||||
|
||||
location = self.stock_location_model.search([('name', '=', 'WH')])
|
||||
self.location = self.stock_location_model.search([('location_id', '=',
|
||||
location.id)])
|
||||
|
||||
# Create account for Goods Received Not Invoiced
|
||||
name = 'Goods Received Not Invoiced'
|
||||
code = 'grni'
|
||||
acc_type = 'equity'
|
||||
self.account_grni = self._create_account(acc_type, name, code,
|
||||
self.company)
|
||||
# Create account for Cost of Goods Sold
|
||||
name = 'Cost of Goods Sold'
|
||||
code = 'cogs'
|
||||
acc_type = 'expense'
|
||||
self.account_cogs = self._create_account(acc_type, name, code,
|
||||
self.company)
|
||||
|
||||
# Create account for Inventory
|
||||
name = 'Inventory'
|
||||
code = 'inventory'
|
||||
acc_type = 'asset'
|
||||
self.account_inventory = self._create_account(acc_type, name, code,
|
||||
self.company)
|
||||
|
||||
# Create account for Inventory Revaluation
|
||||
name = 'Inventory Revaluation'
|
||||
code = 'revaluation'
|
||||
acc_type = 'expense'
|
||||
self.account_revaluation = self._create_account(acc_type, name, code,
|
||||
self.company)
|
||||
|
||||
# Create product category
|
||||
self.product_ctg = self._create_product_category()
|
||||
|
||||
# Create a Product with real cost
|
||||
standard_price = 10.0
|
||||
list_price = 20.0
|
||||
self.product_real = self._create_product('real', standard_price,
|
||||
list_price)
|
||||
# Add default quantity
|
||||
quantity = 20.00
|
||||
self._update_product_qty(self.product_real, self.location, quantity)
|
||||
|
||||
# Create a Product with average cost
|
||||
standard_price = 10.0
|
||||
list_price = 20.0
|
||||
self.product_average = self._create_product('average', standard_price,
|
||||
list_price)
|
||||
|
||||
# Add default quantity
|
||||
quantity = 20.00
|
||||
self._update_product_qty(self.product_average, self.location, quantity)
|
||||
|
||||
def _create_account(self, acc_type, name, code, company):
|
||||
"""Create an account."""
|
||||
type_ids = self.acc_type_model.search([('code', '=', acc_type)])
|
||||
account = self.account_model.create({
|
||||
'name': name,
|
||||
'code': code,
|
||||
'type': 'other',
|
||||
'user_type': type_ids.ids and type_ids.ids[0],
|
||||
'company_id': company.id
|
||||
})
|
||||
return account
|
||||
|
||||
def _create_product_category(self):
|
||||
product_ctg = self.product_ctg_model.create({
|
||||
'name': 'test_product_ctg',
|
||||
'property_stock_valuation_account_id': self.account_inventory.id,
|
||||
'property_inventory_revaluation_increase_account_categ':
|
||||
self.account_revaluation.id,
|
||||
'property_inventory_revaluation_decrease_account_categ':
|
||||
self.account_revaluation.id,
|
||||
})
|
||||
return product_ctg
|
||||
|
||||
def _create_product(self, cost_method, standard_price, list_price):
|
||||
"""Create a Product with inventory valuation set to auto."""
|
||||
product = self.product_model.create({
|
||||
'name': 'test_product',
|
||||
'categ_id': self.product_ctg.id,
|
||||
'type': 'product',
|
||||
'standard_price': standard_price,
|
||||
'list_price': list_price,
|
||||
'valuation': 'real_time',
|
||||
'cost_method': cost_method,
|
||||
'property_stock_account_input': self.account_grni.id,
|
||||
'property_stock_account_output': self.account_cogs.id,
|
||||
})
|
||||
return product
|
||||
|
||||
def _create_inventory_revaluation(self, journal, revaluation_type):
|
||||
"""Create a Inventory Revaluation with revaluation_type set to
|
||||
price_change to recalculate inventory value according to new price."""
|
||||
inventory = self.reval_model.create({
|
||||
'name': 'test_inventory_revaluation',
|
||||
'document_date': datetime.today(),
|
||||
'revaluation_type': revaluation_type,
|
||||
'journal_id': journal.id,
|
||||
})
|
||||
return inventory
|
||||
|
||||
def _create_inventory_revaluation_line(self, revaluation, product):
|
||||
"""Create a Inventory Revaluation line by applying
|
||||
increase and decrease account to it."""
|
||||
self.increase_account_id = product.categ_id and \
|
||||
product.categ_id.\
|
||||
property_inventory_revaluation_increase_account_categ
|
||||
self.decrease_account_id = product.categ_id and \
|
||||
product.categ_id.\
|
||||
property_inventory_revaluation_decrease_account_categ
|
||||
|
||||
line = self.reval_line_model.create({
|
||||
'product_template_id': product.id,
|
||||
'revaluation_id': revaluation.id,
|
||||
'increase_account_id': self.increase_account_id.id,
|
||||
'decrease_account_id': self.decrease_account_id.id,
|
||||
})
|
||||
return line
|
||||
|
||||
def _update_product_qty(self, product, location, quantity):
|
||||
"""Update Product quantity."""
|
||||
product_qty = self.stock_change_model.create({
|
||||
'location_id': location.id,
|
||||
'product_id': product.id,
|
||||
'new_quantity': quantity,
|
||||
})
|
||||
product_qty.change_product_qty()
|
||||
return product_qty
|
||||
|
||||
def _get_quant(self, date_from, line):
|
||||
"""Get Quants for Inventory Revaluation between the date supplied."""
|
||||
quant = self.get_quant_model.create({
|
||||
'date_from': date_from,
|
||||
'date_to': datetime.today(),
|
||||
})
|
||||
line_context = {
|
||||
'active_id': line.id,
|
||||
'active_ids': line.ids,
|
||||
'active_model': 'stock.inventory.revaluation.line',
|
||||
}
|
||||
quant.with_context(line_context).process()
|
||||
for line_quant in line.line_quant_ids:
|
||||
line_quant.new_cost = 8.0
|
||||
|
||||
def test_inventory_revaluation_price_change(self):
|
||||
"""Test that the inventory is revaluated when the
|
||||
inventory price for any product is changed."""
|
||||
|
||||
# Create an Inventory Revaluation
|
||||
revaluation_type = 'price_change'
|
||||
invent_price_change = self._create_inventory_revaluation(
|
||||
self.journal, revaluation_type)
|
||||
|
||||
# Create an Inventory Revaluation Line for real cost product
|
||||
invent_line_real = \
|
||||
self._create_inventory_revaluation_line(
|
||||
invent_price_change, self.product_real.product_tmpl_id)
|
||||
|
||||
# Create an Inventory Revaluation Line Quant
|
||||
date_from = date.today() - timedelta(1)
|
||||
self._get_quant(date_from, invent_line_real)
|
||||
|
||||
# Create an Inventory Revaluation Line for average cost product
|
||||
invent_line_avg = self._create_inventory_revaluation_line(
|
||||
invent_price_change, self.product_average.product_tmpl_id)
|
||||
# Post the inventory revaluation
|
||||
invent_line_avg.new_cost = 8.00
|
||||
|
||||
invent_price_change.button_post()
|
||||
|
||||
expected_result = (10.00 - 8.00) * 20.00
|
||||
for line in invent_price_change.line_ids:
|
||||
for move_line in line.move_id.line_id:
|
||||
if move_line.debit:
|
||||
self.assertEqual(move_line.debit, expected_result,
|
||||
'Incorrect inventory revaluation for '
|
||||
'type Price Change.')
|
||||
|
||||
def test_inventory_revaluation_value_change(self):
|
||||
"""Test that the inventory is revaluated when the
|
||||
inventory price for any product is changed."""
|
||||
# Create an Inventory Revaluation for value change
|
||||
revaluation_type = 'inventory_value'
|
||||
invent_inventory_value = self._create_inventory_revaluation(
|
||||
self.journal, revaluation_type)
|
||||
|
||||
# Create an Inventory Revaluation Line for average cost product
|
||||
invent_line_average = self._create_inventory_revaluation_line(
|
||||
invent_inventory_value, self.product_average.product_tmpl_id)
|
||||
invent_line_average.new_value = 100.00
|
||||
|
||||
# Post the inventory revaluation
|
||||
invent_inventory_value.button_post()
|
||||
|
||||
for line in invent_inventory_value.line_ids:
|
||||
for move_line in line.move_id.line_id:
|
||||
if move_line.debit:
|
||||
self.assertEqual(move_line.debit, 100.0,
|
||||
'Incorrect inventory revaluation for '
|
||||
'type Inventory Debit/Credit.')
|
||||
19
stock_inventory_revaluation/views/product_view.xml
Normal file
19
stock_inventory_revaluation/views/product_view.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_category_property_form" model="ir.ui.view">
|
||||
<field name="name">product.category.stock.property.form.inherit</field>
|
||||
<field name="model">product.category</field>
|
||||
<field name="inherit_id"
|
||||
ref="stock_account.view_category_property_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="account_property" position="inside">
|
||||
<field name="property_inventory_revaluation_increase_account_categ" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="property_inventory_revaluation_decrease_account_categ" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,282 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_form" model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.form</field>
|
||||
<field name="model">stock.inventory.revaluation</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Stock Inventory Revaluation">
|
||||
<header>
|
||||
<button name="button_draft"
|
||||
states="cancel"
|
||||
string="Back to Draft"
|
||||
type="object"/>
|
||||
<button name="button_post" states="draft"
|
||||
string="Post" type="object"
|
||||
class="oe_highlight"/>
|
||||
<button name="button_cancel" states="draft,posted"
|
||||
string="Cancel" type="object"
|
||||
class="oe_highlight"/>
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,done,cancel"
|
||||
statusbar_colors='{"done":"blue"}'/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_edit_only">
|
||||
<label for="name" class="oe_inline"/>
|
||||
</div>
|
||||
<h1>
|
||||
<field name="name" class="oe_inline"/>
|
||||
</h1>
|
||||
<group name="main">
|
||||
<group name="basic">
|
||||
<field name="document_date"/>
|
||||
<field name="revaluation_type"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group name="accounting">
|
||||
<field name="journal_id"/>
|
||||
</group>
|
||||
<group name="remarks" colspan="2">
|
||||
<field name="remarks"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Products">
|
||||
<field name="line_ids" nolabel="1">
|
||||
<tree string="Stock Inventory Revaluation Lines">
|
||||
<field name="state" invisible="True"/>
|
||||
<field name="revaluation_type"
|
||||
invisible="1"/>
|
||||
<field name="product_template_id"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="cost_method"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="old_cost"
|
||||
attrs="{'invisible':['|', '|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real'), ('state', '!=', 'posted')]}"/>
|
||||
<field name="new_cost"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real')]}"/>
|
||||
<field name="old_value"
|
||||
attrs="{'invisible':['|', '|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real'), ('state', '!=', 'posted')]}"/>
|
||||
<field name="current_value"/>
|
||||
<field name="new_value"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real')]}"/>
|
||||
<field name="qty_available"/>
|
||||
<field name="increase_account_id"/>
|
||||
<field name="decrease_account_id"/>
|
||||
<field name="move_id"/>
|
||||
</tree>
|
||||
<form string="Stock Inventory Revaluation Lines">
|
||||
<group>
|
||||
<field name="state" invisible="True"/>
|
||||
<group name="product">
|
||||
<field name="product_template_id"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="cost_method"/>
|
||||
<field name="qty_available"/>
|
||||
<field name="revaluation_type" invisible="1"/>
|
||||
</group>
|
||||
<group name="unit_cost">
|
||||
<field name="old_cost"
|
||||
attrs="{'invisible':['|', '|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real'), ('state', '!=', 'posted')]}"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="new_cost"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real')]}"/>
|
||||
|
||||
</group>
|
||||
<group name="value">
|
||||
<field name="old_value"
|
||||
attrs="{'invisible':['|', '|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real'), ('state', '!=', 'posted')]}"/>
|
||||
<field name="current_value"/>
|
||||
<field name="new_value"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real')]}"/>
|
||||
</group>
|
||||
<group name="accounting">
|
||||
<field name="increase_account_id"/>
|
||||
<field name="decrease_account_id"/>
|
||||
<field name="move_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="quant" string="Quants" attrs="{'invisible':[('cost_method','!=', 'real')]}">
|
||||
<button
|
||||
name="%(action_stock_inventory_revaluation_line_get_quant)d" string="Get Quants" type="action" class="oe_highlight" />
|
||||
<field name="line_quant_ids"
|
||||
nolabel="1">
|
||||
<tree name="quants"
|
||||
string="Quants"
|
||||
create="false"
|
||||
delete="false" editable="bottom">
|
||||
<field name="quant_id"/>
|
||||
<field name="in_date"/>
|
||||
<field name="product_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="qty"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="new_cost"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_line_tree"
|
||||
model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.line.tree</field>
|
||||
<field name="model">stock.inventory.revaluation.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Stock Inventory Revaluation Lines">
|
||||
<field
|
||||
name="revaluation_type"
|
||||
invisible="1"/>
|
||||
<field name="product_template_id"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="cost_method"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="new_cost"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real_price')]}"/>
|
||||
<field name="current_value"/>
|
||||
<field name="new_value"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real_price')]}"/>
|
||||
<field name="qty_available"/>
|
||||
<field name="increase_account_id"/>
|
||||
<field name="decrease_account_id"/>
|
||||
<field name="move_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_line_form"
|
||||
model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.line.form</field>
|
||||
<field name="model">stock.inventory.revaluation.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Stock Inventory Revaluation Lines">
|
||||
<group>
|
||||
<field name="state" invisible="True"/>
|
||||
<group name="product">
|
||||
<field name="product_template_id"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="cost_method"/>
|
||||
<field name="qty_available"/>
|
||||
</group>
|
||||
<group name="unit_cost">
|
||||
<field name="old_cost"
|
||||
attrs="{'invisible':['|', '|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real'), ('state', '!=', 'posted')]}"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="new_cost"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'price_change'), ('cost_method','=', 'real')]}"/>
|
||||
|
||||
</group>
|
||||
<group name="value">
|
||||
<field name="old_value"
|
||||
attrs="{'invisible':['|', '|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real'), ('state', '!=', 'posted')]}"/>
|
||||
<field name="current_value"/>
|
||||
<field name="new_value"
|
||||
attrs="{'invisible':['|', ('revaluation_type', '!=', 'inventory_value'), ('cost_method','=', 'real')]}"/>
|
||||
</group>
|
||||
<group name="accounting">
|
||||
<field name="increase_account_id"/>
|
||||
<field name="decrease_account_id"/>
|
||||
<field name="move_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="quant" string="Quants" attrs="{'invisible':[('cost_method','!=', 'real_price')]}">
|
||||
<field name="line_quant_ids"
|
||||
create="false" delete="false" nolabel="1"
|
||||
editable="bottom"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_line_quant_tree"
|
||||
model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.line.quant.tree</field>
|
||||
<field name="model">stock.inventory.revaluation.line.quant</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Stock Inventory Revaluation Line Quants">
|
||||
<field name="quant_id"/>
|
||||
<field name="in_date"/>
|
||||
<field name="product_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="qty"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="new_cost"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_line_quant_form"
|
||||
model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.line.quant.form</field>
|
||||
<field name="model">stock.inventory.revaluation.line.quant</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Stock Inventory Revaluation Line Quants">
|
||||
<field name="quant_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="qty"/>
|
||||
<field name="current_cost"/>
|
||||
<field name="new_cost"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_tree" model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.tree</field>
|
||||
<field name="model">stock.inventory.revaluation</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Stock Inventory Revaluation">
|
||||
<field name="name"/>
|
||||
<field name="revaluation_type"/>
|
||||
<field name="document_date"/>
|
||||
<field name="state"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_revaluation_search" model="ir.ui.view">
|
||||
<field name="name">stock.inventory.revaluation.search</field>
|
||||
<field name="model">stock.inventory.revaluation</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Stock Inventory Revaluation">
|
||||
<field name="name"/>
|
||||
<field name="revaluation_type"/>
|
||||
<field name="document_date"/>
|
||||
<field name="state"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="line_ids"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_stock_inventory_revaluation_tree" model="ir.actions.act_window">
|
||||
<field name="name">Inventory Revaluation</field>
|
||||
<field name="res_model">stock.inventory.revaluation</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to start a new Stock Inventory Revaluation.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_stock_inventory_revaluation_tree"
|
||||
id="menu_action_stock_inventory_revaluation_tree"
|
||||
parent="stock.menu_stock_inventory_control"
|
||||
groups="stock_account.group_inventory_valuation"/>
|
||||
</data>
|
||||
</openerp>
|
||||
6
stock_inventory_revaluation/wizards/__init__.py
Normal file
6
stock_inventory_revaluation/wizards/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import stock_inventory_revaluation_get_quants
|
||||
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eficent Business and IT Consulting Services S.L.
|
||||
# - Jordi Ballester Alomar
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class StockInventoryRevaluationGetQuants(models.TransientModel):
|
||||
|
||||
_name = 'stock.inventory.revaluation.line.get.quant'
|
||||
_description = 'Inventory revaluation line get Quants'
|
||||
|
||||
date_from = fields.Date('Date From')
|
||||
|
||||
date_to = fields.Date('Date To')
|
||||
|
||||
def _get_quant_search_criteria(self, product_variant):
|
||||
domain = [('product_id', '=', product_variant.id),
|
||||
('location_id.usage', '=', 'internal')]
|
||||
if self.date_from:
|
||||
domain.extend([('in_date', '>=', self.date_from)])
|
||||
if self.date_to:
|
||||
domain.extend([('in_date', '<=', self.date_to)])
|
||||
|
||||
return domain
|
||||
|
||||
def _select_quants(self, line):
|
||||
quant_l = []
|
||||
quant_obj = self.env['stock.quant']
|
||||
for prod_variant in line.product_template_id.product_variant_ids:
|
||||
search_domain = self._get_quant_search_criteria(prod_variant)
|
||||
quants = quant_obj.search(search_domain)
|
||||
for quant in quants:
|
||||
quant_l.append(quant)
|
||||
return quant_l
|
||||
|
||||
def _prepare_line_quant_data(self, line, quant):
|
||||
return {
|
||||
'line_id': line.id,
|
||||
'quant_id': quant.id,
|
||||
'new_cost': quant.cost
|
||||
}
|
||||
|
||||
@api.one
|
||||
def process(self):
|
||||
if self.env.context.get('active_id', False):
|
||||
line_obj = self.env['stock.inventory.revaluation.line']
|
||||
line_quant_obj = self.env['stock.inventory.revaluation.line.quant']
|
||||
line = line_obj.browse(self.env.context['active_id'])
|
||||
# Delete the previous records
|
||||
for line_quant in line.line_quant_ids:
|
||||
line_quant.unlink()
|
||||
|
||||
quants = self._select_quants(line)
|
||||
for q in quants:
|
||||
q_data = self._prepare_line_quant_data(line, q)
|
||||
line_quant_obj.create(q_data)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view"
|
||||
id="stock_inventory_revaluation_line_get_quant_form">
|
||||
<field name="name">stock.inventory.revaluation.line.get.quant.form</field>
|
||||
<field name="model">stock.inventory.revaluation.line.get.quant</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Get Quants">
|
||||
<group colspan="2" col="2">
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="process" string="Get Quants" type="object"
|
||||
class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_stock_inventory_revaluation_line_get_quant"
|
||||
model="ir.actions.act_window">
|
||||
<field name="name">Get Quants for Inventory Revaluation</field>
|
||||
<field name="res_model">stock.inventory.revaluation.line.get.quant</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id"
|
||||
ref="stock_inventory_revaluation_line_get_quant_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user