[ADD] Migrated stock_inventory_revaluation module to v9.

This commit is contained in:
SerpentCS
2016-10-27 17:12:46 +05:30
committed by Jordi Ballester Alomar
parent e09236987c
commit f49bd66d9c
21 changed files with 454 additions and 229 deletions

View File

@@ -12,19 +12,17 @@ inventory revaluation.
You can re-valuate inventory values by:
* Changing the inventory valuation of a specific product. The cost price
is changed, and the inventory value is recalculated according to the new
price. In case of real price, you can select on which quants you want to
change the unit cost.
is changed, and the inventory value is recalculated according to the new
price. In case of real price, you can select on which quants you want to
change the unit cost.
* 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
@@ -49,7 +47,7 @@ Usage
.. 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
:target: https://runbot.odoo-community.org/runbot/153/9.0
Bug Tracker
===========
@@ -58,10 +56,7 @@ 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**>`_.
welcomed feedback.
Credits
=======
@@ -75,14 +70,14 @@ Contributors
------------
* Eficent Business and IT Consulting Services S.L. <contact@eficent.com>
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
:target: https://odoo-community.org
This module is maintained by the OCA.
@@ -90,4 +85,4 @@ 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.
To contribute to this module, please visit https://odoo-community.org.

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import models
from . import wizards

View File

@@ -1,14 +1,17 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# 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",
"version": "9.0.1.0.0",
"author": "Eficent Business and IT Consulting Services S.L., "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
"website": "http://www.eficent.com",
"category": "Warehouse",
@@ -20,6 +23,7 @@
"security/ir.model.access.csv",
"views/stock_inventory_revaluation_view.xml",
"views/product_view.xml",
"views/account_move_line_view.xml",
"data/stock_inventory_revaluation_data.xml",
"wizards/stock_inventory_revaluation_mass_post_view.xml",
],

View File

@@ -2,12 +2,6 @@
<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>

View File

@@ -0,0 +1,4 @@
---Fields in module 'stock_inventory_revaluation'---
stock_inventory_revaluation / stock.inventory.revaluation / product_id (many2one) : NEW relation: product.product, required: required
---XML records in module 'stock_inventory_revaluation'---
DEL ir.sequence.type: stock_inventory_revaluation.sequence_stock_inventory_revaluation_type

View File

@@ -0,0 +1,10 @@
---Fields in module 'stock_inventory_revaluation'---
stock_inventory_revaluation / stock.inventory.revaluation / product_id (many2one) : NEW relation: product.product, required: required
# TODO : Create as many IR records for each product variants of the template
# DONE : in post-migration script
---XML records in module 'stock_inventory_revaluation'---
DEL ir.sequence.type: stock_inventory_revaluation.sequence_stock_inventory_revaluation_type
# NOTHING TO DO: Sequence type deprecated in v9

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# © 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import api, SUPERUSER_ID
from openupgradelib import openupgrade
def migrate_inventory_revaluation(env):
revaluations = env['stock.inventory.revaluation'].search([])
for revaluation in revaluations:
product_variants = revaluation.product_template_id.\
with_context(active_test=False).product_variant_ids.mapped('id')
if revaluation.product_template_id and\
revaluation.product_template_id.product_variant_count > 1:
for product_id in product_variants[1:]:
new_revaluation = revaluation.\
copy(default={'product_id': product_id,
'state': 'posted',
'account_move_id': revaluation.
account_move_id.id})
quants = env['stock.inventory.revaluation.quant'].\
search([('product_id', '=', product_id),
('revaluation_id', '=', revaluation.id)])
if quants:
quants.write({'revaluation_id': new_revaluation.id})
if product_variants:
prod_dict = {'product_id': product_variants[0]}
revaluation.write(prod_dict)
@openupgrade.migrate()
def migrate(cr, version):
env = api.Environment(cr, SUPERUSER_ID, {})
migrate_inventory_revaluation(env)

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# © 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(cr, version):
pass

View File

@@ -1,7 +1,10 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import product
from . import account_move
from . import stock_inventory_revaluation

View File

@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import api, exceptions, fields, models, _
class AccountMove(models.Model):
_inherit = 'account.move'
stock_inventory_revaluation_id = fields.Many2one(
comodel_name='stock.inventory.revaluation',
string='Stock Inventory Revaluation',
ondelete='restrict', copy=False)
@api.multi
def unlink(self):
for rec in self:
if rec.stock_inventory_revaluation_id:
raise exceptions.Warning(
_("You cannot remove the journal item that is related "
"to an inventory revaluation"))
return super(AccountMove, self).unlink()
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
stock_inventory_revaluation_id = fields.Many2one(
comodel_name='stock.inventory.revaluation',
related='move_id.stock_inventory_revaluation_id',
string='Stock Inventory Revaluation',
store=True, ondelete='restrict', copy=False)
@api.multi
def unlink(self):
for rec in self:
if rec.stock_inventory_revaluation_id:
raise exceptions.Warning(
_("You cannot remove the journal item that is related "
"to an inventory revaluation"))
return super(AccountMoveLine, self).unlink()

View File

@@ -1,7 +1,10 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import api, fields, models
@@ -26,30 +29,30 @@ class ProductCategory(models.Model):
"is decreased.")
class ProductTemplate(models.Model):
class Product(models.Model):
_inherit = 'product.template'
_inherit = 'product.product'
@api.multi
def do_change_standard_price(self, new_price):
"""Override standard method, as it was not suitable."""
reval_model = self.env["stock.inventory.revaluation"]
for product_template in self:
for product in self:
increase_account_id = \
product_template.categ_id.\
product.categ_id.\
property_inventory_revaluation_increase_account_categ.id \
or False
decrease_account_id = \
product_template.categ_id.\
product.categ_id.\
property_inventory_revaluation_decrease_account_categ.id \
or False
reval = reval_model.create({
'revaluation_type': 'price_change',
'product_template_id': product_template.id,
'product_id': product.id,
'new_cost': new_price,
'increase_account_id': increase_account_id,
'decrease_account_id': decrease_account_id
})
reval.post()
reval.button_post()
return True

View File

@@ -1,11 +1,14 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# 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
from openerp.exceptions import UserError
class StockInventoryRevaluation(models.Model):
@@ -19,23 +22,24 @@ class StockInventoryRevaluation(models.Model):
return res and res[0] or False
@api.multi
def _get_product_template_qty(self):
def _compute_get_product_qty(self):
for revaluation in self:
revaluation.qty_available = 0
for prod_variant in \
revaluation.product_template_id.product_variant_ids:
revaluation.product_id:
revaluation.qty_available += prod_variant.qty_available
@api.multi
def _calc_product_template_value(self):
def _compute_calc_product_value(self):
quant_obj = self.env['stock.quant']
for revaluation in self:
qty_available = 0
current_value = 0.0
for prod_variant in \
revaluation.product_template_id.product_variant_ids:
revaluation.product_id:
qty_available += prod_variant.qty_available
if revaluation.product_template_id.cost_method == 'real':
if revaluation.product_id.\
cost_method == 'real':
quants = quant_obj.search([('product_id', '=',
prod_variant.id),
('location_id.usage', '=',
@@ -44,8 +48,7 @@ class StockInventoryRevaluation(models.Model):
current_value += quant.cost
else:
current_value = \
revaluation.product_template_id.standard_price * \
qty_available
prod_variant.standard_price * qty_available
revaluation.current_value = current_value
name = fields.Char('Reference',
@@ -108,12 +111,19 @@ class StockInventoryRevaluation(models.Model):
readonly=True,
states={'draft': [('readonly', False)]})
product_template_id = fields.Many2one('product.template', 'Product',
required=True,
domain=[('type', '=', 'product')])
product_id = fields.Many2one('product.product', 'Product',
required=True,
domain=[('type', '=', 'product')],
states={'draft': [('readonly', False)]},
readonly=True)
cost_method = fields.Selection(string="Cost Method", readonly=True,
related='product_template_id.cost_method')
product_template_id = fields.Many2one('product.template',
'Product Template',
related='product_id.product_tmpl_id',
store=True)
cost_method = fields.Char(string="Cost Method", readonly=True,
related='product_id.cost_method')
uom_id = fields.Many2one('product.uom', 'UoM', readonly=True,
related="product_template_id.uom_id")
@@ -128,20 +138,22 @@ class StockInventoryRevaluation(models.Model):
help='Displays the current cost of the '
'product.',
digits=dp.get_precision('Product Price'),
compute="_calc_current_cost",
compute="_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'))
digits=dp.get_precision('Product Price'),
states={'draft': [('readonly', False)]},
readonly=True)
current_value = fields.Float('Current value',
help='Displays the current value of the '
'product.',
digits=dp.get_precision('Account'),
compute="_calc_product_template_value",
compute="_compute_calc_product_value",
readonly=True)
old_value = fields.Float('Old value',
@@ -158,7 +170,7 @@ class StockInventoryRevaluation(models.Model):
digits=dp.get_precision('Account'))
qty_available = fields.Float(
'Quantity On Hand', compute='_get_product_template_qty',
'Quantity On Hand', compute='_compute_get_product_qty',
digits_compute=dp.get_precision('Product Unit of Measure'))
increase_account_id = fields.Many2one(
@@ -166,128 +178,192 @@ class StockInventoryRevaluation(models.Model):
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.")
"the revaluation.",
states={'draft': [('readonly', False)]},
readonly=True)
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.")
"Account is used when the inventory value is decreased.",
states={'draft': [('readonly', False)]},
readonly=True)
account_move_id = fields.Many2one('account.move', 'Account move',
readonly=True, copy=False)
account_move_ids = fields.One2many(
comodel_name='account.move',
inverse_name='stock_inventory_revaluation_id',
readonly=True)
post_date = fields.Datetime(
'Posting Date',
help="Date of actual processing",
states={'draft': [('readonly', False)]},
readonly=True)
reval_quant_ids = fields.One2many('stock.inventory.revaluation.quant',
'revaluation_id',
string='Revaluation line quants')
@api.multi
@api.depends("product_template_id", "product_template_id.standard_price")
def _calc_current_cost(self):
@api.depends("product_id", "product_id.standard_price")
def _compute_calc_current_cost(self):
for revaluation in self:
revaluation.current_cost = \
revaluation.product_template_id.standard_price
revaluation.product_id.standard_price
@api.multi
@api.constrains('product_template_id', 'company_id')
def _check_is_stockable(self):
for revaluation in self:
if revaluation.product_template_id.type != 'product':
raise UserError(_('Configuration error!\nThe product must be '
'stockable.'))
@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.\
@api.onchange("product_id")
def _onchange_product_product_id(self):
if self.product_id:
self.increase_account_id = self.product_id.categ_id and \
self.product_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.\
self.decrease_account_id = self.product_id.categ_id and \
self.product_id.categ_id.\
property_inventory_revaluation_decrease_account_categ
@api.model
def _prepare_move_data(self, date_move):
period = self.env['account.period'].find(date_move)[0]
return {
'narration': self.remarks,
'date': date_move,
'ref': self.name,
'journal_id': self.journal_id.id,
'period_id': period.id,
'stock_inventory_revaluation_id': self.id
}
@api.model
def _prepare_debit_move_line_data(self, amount, account_id, prod_id):
def _prepare_debit_move_line_data(self, move, amount, account_id, prod_id):
return {
'name': self.name,
'date': self.account_move_id.date,
'date': move.date,
'product_id': prod_id,
'account_id': account_id,
'move_id': self.account_move_id.id,
'move_id': move.id,
'debit': amount
}
@api.model
def _prepare_credit_move_line_data(self, amount, account_id, prod_id):
def _prepare_credit_move_line_data(self, move, amount, account_id,
prod_id):
return {
'name': self.name,
'date': self.account_move_id.date,
'date': move.date,
'product_id': prod_id,
'account_id': account_id,
'move_id': self.account_move_id.id,
'move_id': move.id,
'credit': amount
}
@api.model
def _create_accounting_entry(self, amount_diff):
def _create_accounting_entry(self):
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.account_move_id = self.env['account.move'].create(move_data).id
datas = self.product_template_id.get_product_accounts()
move_line_obj = self.env['account.move.line']
stock_valuation_account_id = False
if datas.get('stock_valuation'):
stock_valuation_account_id = datas.get('stock_valuation').id
if not stock_valuation_account_id:
raise UserError(_("Please add Stock Valuation Account in "
"Product Category"))
if not self.decrease_account_id or not self.increase_account_id:
raise UserError(_("Please add an Increase Account and "
"a Decrease Account."))
prec = self.env['decimal.precision'].precision_get('Account')
for prod_variant in self.product_id:
amount_diff = 0.0
if self.product_id.cost_method == 'real':
for reval_quant in self.reval_quant_ids:
if reval_quant.product_id == prod_variant:
amount_diff += reval_quant.get_total_value()
if amount_diff == 0.0:
return True
else:
if self.revaluation_type == 'price_change':
diff = self.old_cost - self.new_cost
amount_diff = prod_variant.qty_available * diff
else:
proportion = prod_variant.qty_available / \
self.product_template_id.qty_available
amount_diff = round(self.new_value * proportion, prec)
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.account_move_id.journal_id.entry_posted:
self.account_move_id.post()
qty = prod_variant.qty_available
if qty:
if amount_diff > 0:
debit_account_id = self.decrease_account_id.id
credit_account_id = \
datas.get('stock_valuation').id
else:
debit_account_id = \
datas.get('stock_valuation').id
credit_account_id = self.increase_account_id.id
move = self.env['account.move'].create(move_data)
move_line_data = self._prepare_debit_move_line_data(
move, abs(amount_diff), debit_account_id, prod_variant.id)
move_line_obj.with_context({'check_move_validity':
False}).create(move_line_data)
move_line_data = self._prepare_credit_move_line_data(
move, abs(amount_diff), credit_account_id, prod_variant.id)
move_line_obj.create(move_line_data)
move.post()
@api.multi
def post(self):
for revaluation in self:
if revaluation.product_id.\
cost_method == 'real':
for reval_quant in revaluation.reval_quant_ids:
reval_quant.write_new_cost()
else:
if revaluation.product_id.\
cost_method in ['standard', 'average']:
if revaluation.revaluation_type == 'inventory_value':
if revaluation.new_value < 0:
raise UserError(
_("The new value for product %s cannot "
"be negative" %
revaluation.product_template_id.name))
for variant in revaluation.product_id:
if variant.qty_available <= 0.0:
raise UserError(
_("Cannot do an inventory value change if the "
"quantity available for product %s "
"is 0 or negative" %
variant.name))
if revaluation.revaluation_type == 'price_change':
revaluation.old_cost = revaluation.current_cost
revaluation.product_id.write(
{'standard_price': revaluation.new_cost})
else:
revaluation.old_cost = revaluation.current_cost
revaluation.old_value = revaluation.current_value
value_diff = revaluation.current_value - \
revaluation.new_value
new_cost = value_diff / revaluation.qty_available
revaluation.product_id.write(
{'standard_price': new_cost})
if revaluation.product_id.categ_id.\
property_valuation == 'real_time':
revaluation._create_accounting_entry()
self.post_date = fields.Datetime.now()
self.state = 'posted'
amount_diff = 0.0
if revaluation.product_template_id.cost_method == 'real':
diff = 0.0
if revaluation.product_id.\
cost_method == 'real':
for reval_quant in revaluation.reval_quant_ids:
amount_diff += reval_quant.get_total_value()
reval_quant.write_new_cost()
if amount_diff == 0.0:
return True
else:
if revaluation.product_template_id.cost_method \
in ['standard', 'average']:
if revaluation.product_id.\
cost_method in ['standard', 'average']:
if revaluation.revaluation_type == 'price_change':
diff = revaluation.current_cost - revaluation.new_cost
amount_diff = revaluation.qty_available * diff
@@ -306,22 +382,6 @@ class StockInventoryRevaluation(models.Model):
"is 0 or negative" %
revaluation.product_template_id.name))
if revaluation.revaluation_type == 'price_change':
revaluation.old_cost = revaluation.current_cost
revaluation.product_template_id.write(
{'standard_price': revaluation.new_cost})
else:
revaluation.old_cost = revaluation.current_cost
revaluation.old_value = revaluation.current_value
value_diff = revaluation.current_value - \
revaluation.new_value
new_cost = value_diff / revaluation.qty_available
revaluation.product_template_id.write(
{'standard_price': new_cost})
if revaluation.product_template_id.valuation == 'real_time':
revaluation._create_accounting_entry(amount_diff)
@api.model
def create(self, values):
sequence_obj = self.env['ir.sequence']
@@ -332,7 +392,6 @@ class StockInventoryRevaluation(models.Model):
@api.multi
def button_post(self):
self.post()
self.write({'state': 'posted'})
return True
@api.multi
@@ -342,19 +401,16 @@ class StockInventoryRevaluation(models.Model):
@api.multi
def button_cancel(self):
moves = self.env['account.move']
for revaluation in self:
if revaluation.account_move_id:
moves += revaluation.account_move_id
for reval_quant in revaluation.reval_quant_ids:
reval_quant.quant_id.write({'cost': reval_quant.old_cost})
if moves:
if revaluation.account_move_ids:
# second, invalidate the move(s)
moves.button_cancel()
revaluation.account_move_ids.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()
revaluation.account_move_ids.unlink()
revaluation.state = 'cancel'
return True
@@ -405,17 +461,20 @@ class StockInventoryRevaluationQuant(models.Model):
comodel_name='res.company', string='Company', readonly=True,
related="revaluation_id.company_id")
@api.model
def get_total_value(self):
amount_diff = 0.0
if self.product_id.product_tmpl_id.cost_method == 'real':
if self.product_id.\
cost_method == 'real':
if self.revaluation_id.revaluation_type != 'price_change':
raise UserError(_("You can only post quant cost changes."))
else:
diff = self.current_cost - self.new_cost
diff = self.old_cost - self.new_cost
amount_diff = self.qty * diff
return amount_diff
@api.model
def write_new_cost(self):
self.old_cost = self.current_cost
self.quant_id.write({'cost': self.new_cost})
self.quant_id.sudo().write({'cost': self.new_cost})
return True

View File

@@ -1,3 +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_quant,stock.inventory.revaluation.quant,model_stock_inventory_revaluation_quant,stock_account.group_inventory_valuation,1,1,1,1
access_stock_inventory_revaluation_quant,stock.inventory.revaluation.quant,model_stock_inventory_revaluation_quant,stock_account.group_inventory_valuation,1,1,1,1
access_stock_inventory_revaluation_account_user,stock.inventory.revaluation.account.user,model_stock_inventory_revaluation,account.group_account_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_inventory_revaluation stock.inventory.revaluation model_stock_inventory_revaluation stock_account.group_inventory_valuation 1 1 1 1
3 access_stock_inventory_revaluation_quant stock.inventory.revaluation.quant model_stock_inventory_revaluation_quant stock_account.group_inventory_valuation 1 1 1 1
4 access_stock_inventory_revaluation_account_user stock.inventory.revaluation.account.user model_stock_inventory_revaluation account.group_account_user 1 0 0 0

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import test_stock_inventory_revaluation

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# (<http://www.serpentcs.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp.tests.common import TransactionCase
@@ -16,56 +18,54 @@ class TestStockInventoryRevaluation(TransactionCase):
super(TestStockInventoryRevaluation, self).setUp()
# Get required Model
self.product_model = self.env['product.product']
self.template_model = self.env['product.template']
self.product_ctg_model = self.env['product.category']
self.reval_model = self.env['stock.inventory.revaluation']
self.account_model = self.env['account.account']
self.acc_type_model = self.env['account.account.type']
self.reval_quant_model = self.\
env['stock.inventory.revaluation.quant']
self.get_quant_model = self.\
env['stock.inventory.revaluation.get.quant']
self.mass_post_model = self.\
env['stock.inventory.revaluation.mass.post']
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)])
# Account types
expense_type = self.env.ref('account.data_account_type_expenses')
equity_type = self.env.ref('account.data_account_type_equity')
asset_type = self.env.ref('account.data_account_type_fixed_assets')\
# Create account for Goods Received Not Invoiced
name = 'Goods Received Not Invoiced'
code = 'grni'
acc_type = 'equity'
acc_type = equity_type
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'
acc_type = expense_type
self.account_cogs = self._create_account(acc_type, name, code,
self.company)
# Create account for Inventory
name = 'Inventory'
code = 'inventory'
acc_type = 'asset'
acc_type = asset_type
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'
acc_type = expense_type
self.account_revaluation = self._create_account(acc_type, name, code,
self.company)
@@ -75,30 +75,39 @@ class TestStockInventoryRevaluation(TransactionCase):
# 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)
self.product_real_1 = self._create_product('real', standard_price,
False, list_price)
self.product_real_2 = self._create_product(
False, False, self.product_real_1.product_tmpl_id, list_price)
# Add default quantity
quantity = 20.00
self._update_product_qty(self.product_real, self.location, quantity)
quantity = 10.00
self._update_product_qty(self.product_real_1, self.location, quantity)
self._update_product_qty(self.product_real_2, 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)
self.product_average_1 = self._create_product('average',
standard_price,
False,
list_price)
self.product_average_2 = self._create_product(
False, False, self.product_average_1.product_tmpl_id, list_price)
# Add default quantity
quantity = 20.00
self._update_product_qty(self.product_average, self.location, quantity)
quantity = 10.00
self._update_product_qty(self.product_average_1, self.location,
quantity)
self._update_product_qty(self.product_average_2, 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],
'user_type_id': acc_type.id,
'company_id': company.id
})
return account
@@ -111,25 +120,31 @@ class TestStockInventoryRevaluation(TransactionCase):
self.account_revaluation.id,
'property_inventory_revaluation_decrease_account_categ':
self.account_revaluation.id,
'property_valuation': 'real_time'
})
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,
})
def _create_product(self, cost_method, standard_price, template,
list_price):
"""Create a Product variant."""
if not template:
template = self.template_model.create({
'name': 'test_product',
'categ_id': self.product_ctg.id,
'type': 'product',
'standard_price': standard_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 template.product_variant_ids[0]
product = self.product_model.create(
{'product_tmpl_id': template.id,
'list_price': list_price})
return product
def _create_inventory_revaluation(self, journal, revaluation_type,
def _create_inventory_revaluation(self, revaluation_type,
product):
"""Create a Inventory Revaluation by applying
increase and decrease account to it."""
@@ -144,8 +159,7 @@ class TestStockInventoryRevaluation(TransactionCase):
'name': 'test_inventory_revaluation',
'document_date': datetime.today(),
'revaluation_type': revaluation_type,
'journal_id': journal.id,
'product_template_id': product.id,
'product_id': product.id,
'increase_account_id': self.increase_account_id.id,
'decrease_account_id': self.decrease_account_id.id,
})
@@ -195,13 +209,12 @@ class TestStockInventoryRevaluation(TransactionCase):
"""Test that the inventory is revaluated when the
inventory price for a product managed under real costing method is
changed."""
# Create an Inventory Revaluation for real cost product
revaluation_type = 'price_change'
invent_price_change_real = \
self._create_inventory_revaluation(
self.journal, revaluation_type,
self.product_real.product_tmpl_id)
revaluation_type,
self.product_real_1)
# Create an Inventory Revaluation Line Quant
date_from = date.today() - timedelta(1)
@@ -209,11 +222,14 @@ class TestStockInventoryRevaluation(TransactionCase):
invent_price_change_real.button_post()
expected_result = (10.00 - 8.00) * 20.00
expected_result = (10.00 - 8.00) * 10.00
self.assertEqual(len(
invent_price_change_real.account_move_ids[0].line_ids), 2,
'Incorrect accounting entry generated')
for move_line in invent_price_change_real.account_move_id.line_id:
if move_line.debit:
self.assertEqual(move_line.debit, expected_result,
for move_line in invent_price_change_real.account_move_ids[0].line_ids:
if move_line.account_id == self.account_inventory:
self.assertEqual(move_line.credit, expected_result,
'Incorrect inventory revaluation for '
'type Price Change.')
@@ -221,9 +237,8 @@ class TestStockInventoryRevaluation(TransactionCase):
revaluation_type = 'price_change'
# Create an Inventory Revaluation for average cost product
invent_price_change_average = self._create_inventory_revaluation(
self.journal, revaluation_type,
self.product_average.product_tmpl_id)
# Post the inventory revaluation
revaluation_type,
self.product_average_1)
invent_price_change_average.new_cost = 8.00
return invent_price_change_average
@@ -233,21 +248,39 @@ class TestStockInventoryRevaluation(TransactionCase):
changed."""
invent_price_change_average = \
self.create_inventory_revaluation_price_change_average()
# Post the inventory revaluation
invent_price_change_average.button_post()
expected_result = (10.00 - 8.00) * 20.00
for move_line in invent_price_change_average.account_move_id.line_id:
if move_line.debit:
self.assertEqual(move_line.debit, expected_result,
expected_result = (10.00 - 8.00) * 10.00
self.assertEqual(len(
invent_price_change_average.account_move_ids[0].line_ids), 2,
'Incorrect accounting entry generated')
for move_line in \
invent_price_change_average.account_move_ids[0].line_ids:
if move_line.account_id == self.account_inventory:
self.assertEqual(move_line.credit, expected_result,
'Incorrect inventory revaluation for '
'type Price Change.')
'Standard Product .')
# Set the standard price and assert the amount changed
context = {'active_model': u'product.product',
'active_ids': self.product_average_1.ids,
'active_id': self.product_average_1.id}
self.product_average_1.with_context(context).\
do_change_standard_price(5.00)
if self.product_average_1:
self.assertEqual(self.product_average_1.standard_price, 5.0,
'Incorrect Product Price.')
def create_inventory_revaluation_value_change(self):
# Create an Inventory Revaluation for value change for average
# cost product
revaluation_type = 'inventory_value'
invent_value_change = self._create_inventory_revaluation(
self.journal, revaluation_type,
self.product_average.product_tmpl_id)
revaluation_type,
self.product_average_1)
invent_value_change.new_value = 100.00
return invent_value_change
@@ -258,9 +291,13 @@ class TestStockInventoryRevaluation(TransactionCase):
# Post the inventory revaluation
invent_value_change.button_post()
for move_line in invent_value_change.account_move_id.line_id:
if move_line.debit:
self.assertEqual(move_line.debit, 100.0,
self.assertEqual(len(
invent_value_change.account_move_ids[0].line_ids), 2,
'Incorrect accounting entry generated')
for move_line in invent_value_change.account_move_ids[0].line_ids:
if move_line.account_id == self.account_inventory:
self.assertEqual(move_line.credit, 50.0,
'Incorrect inventory revaluation for '
'type Inventory Debit/Credit.')

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_move_line_form" model="ir.ui.view">
<field name="name">account.move.line.form</field>
<field name="model">account.move.line</field>
<field name="inherit_id"
ref="account.view_move_line_form"/>
<field name="arch" type="xml">
<field name="quantity" position="before">
<field name="stock_inventory_revaluation_id"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -9,8 +9,8 @@
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','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_inventory_revaluation_decrease_account_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_inventory_revaluation_increase_account_categ"/>
<field name="property_inventory_revaluation_decrease_account_categ"/>
</group>
</field>
</record>

View File

@@ -32,6 +32,7 @@
<group name="main">
<group name="basic">
<field name="document_date"/>
<field name="post_date"/>
<field name="user_id"/>
<field name="revaluation_type"/>
<field name="company_id" groups="base.group_multi_company"/>
@@ -45,7 +46,8 @@
</group>
<group>
<group name="product">
<field name="product_template_id"/>
<field name="product_id"/>
<field name="product_template_id" readonly="1"/>
<field name="uom_id"/>
<field name="cost_method"/>
<field name="qty_available"/>
@@ -68,7 +70,6 @@
<group name="accounting">
<field name="increase_account_id"/>
<field name="decrease_account_id"/>
<field name="account_move_id"/>
</group>
</group>
<notebook>
@@ -93,6 +94,10 @@
</tree>
</field>
</page>
<page name="account_moves"
string="Journal Entries">
<field name="account_move_ids" nolabel="1"/>
</page>
</notebook>
</sheet>
</form>
@@ -121,7 +126,6 @@
<field name="qty_available"/>
<field name="increase_account_id"/>
<field name="decrease_account_id"/>
<field name="account_move_id"/>
<field name="state"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
@@ -170,6 +174,7 @@
<field name="product_template_id"/>
<field name="revaluation_type"/>
<field name="document_date"/>
<field name="post_date"/>
<field name="state"/>
<field name="company_id" groups="base.group_multi_company"/>
</search>

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# © 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import stock_inventory_revaluation_get_quants

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# © 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import api, fields, models
@@ -28,7 +29,7 @@ class StockInventoryRevaluationGetQuants(models.TransientModel):
quant_l = []
quant_obj = self.env['stock.quant']
for prod_variant in \
revaluation.product_template_id.product_variant_ids:
revaluation.product_id:
search_domain = self._get_quant_search_criteria(prod_variant)
quants = quant_obj.search(search_domain)
for quant in quants:

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L.
# - Jordi Ballester Alomar
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# © 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import api, models, _, exceptions
@@ -10,21 +11,11 @@ class StockInventoryRevaluationMassPost(models.TransientModel):
_name = 'stock.inventory.revaluation.mass.post'
_description = 'Post multiple inventory revaluations'
@api.model
def default_get(self, fields):
res = super(StockInventoryRevaluationMassPost, self).default_get(
fields)
revaluation_ids = self.env.context['active_ids'] or []
active_model = self.env.context['active_model']
if not revaluation_ids:
return res
assert active_model == 'stock.inventory.revaluation', \
'Bad context propagation'
return res
@api.multi
def process(self):
active_model = self.env.context['active_model']
assert active_model == 'stock.inventory.revaluation', \
'Bad context propagation'
self.ensure_one()
revaluation_ids = self.env.context.get('active_ids', [])
revaluation_obj = self.env['stock.inventory.revaluation']