diff --git a/CHANGELOG b/CHANGELOG
index ac649ee2e9..904e369bfb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,5 @@
+* Updating cost price must update stock accounting
+
Version 2.4.0 - 2012-04-23
* Bug fixes (see mercurial logs for details)
* Create move also from supplier to customer
diff --git a/account.py b/account.py
index 3ebcaa91ac..4d677fad21 100644
--- a/account.py
+++ b/account.py
@@ -1,7 +1,7 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.model import Model, fields
-from trytond.pyson import Eval, Bool
+from trytond.pyson import Eval, Bool, Get
class Configuration(Model):
@@ -12,5 +12,9 @@ class Configuration(Model):
states={
'required': Bool(Eval('context', {}).get('company')),
}))
+ cost_price_counterpart_account = fields.Property(fields.Many2One(
+ 'account.account', 'Cost Price Counterpart Account', domain=[
+ ('company', 'in', [Get(Eval('context', {}), 'company'), None]),
+ ]))
Configuration()
diff --git a/account.xml b/account.xml
index 3817036ab0..1482cee775 100644
--- a/account.xml
+++ b/account.xml
@@ -15,6 +15,8 @@ this repository contains the full copyright notices and license terms. -->
+
+
diff --git a/configuration.py b/configuration.py
new file mode 100644
index 0000000000..699339066b
--- /dev/null
+++ b/configuration.py
@@ -0,0 +1,15 @@
+# This file is part of Tryton. The COPYRIGHT file at the top level of this
+# repository contains the full copyright notices and license terms.
+from trytond.model import ModelSingleton, ModelView, fields
+from trytond.pyson import Eval, Get
+
+
+class Configuration(ModelSingleton, ModelView):
+ _name = 'stock.configuration'
+
+ cost_price_counterpart_account = fields.Property(fields.Many2One(
+ 'account.account', 'Cost Price Counterpart Account', domain=[
+ ('company', 'in', [Get(Eval('context', {}), 'company'), False]),
+ ]))
+
+Configuration()
diff --git a/configuration.xml b/configuration.xml
new file mode 100644
index 0000000000..72e6fbb60d
--- /dev/null
+++ b/configuration.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ stock.configuration
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
diff --git a/product.py b/product.py
index dc1c202ad4..ff65face2d 100644
--- a/product.py
+++ b/product.py
@@ -1,7 +1,12 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
+import copy
+from decimal import Decimal
from trytond.model import ModelView, ModelSQL, fields
-from trytond.pyson import Eval
+from trytond.wizard import Wizard, StateView, StateTransition, Button
+from trytond.pyson import Eval, Get
+from trytond.transaction import Transaction
+from trytond.pool import Pool
class Category(ModelSQL, ModelView):
@@ -135,4 +140,180 @@ class Template(ModelSQL, ModelView):
account_stock_lost_found_used = fields.Function(fields.Many2One(
'account.account', 'Account Stock Lost and Found'), 'get_account')
+ def __init__(self):
+ super(Template, self).__init__()
+ self.cost_price = copy.copy(self.cost_price)
+ self.cost_price.states = copy.copy(self.cost_price.states)
+ self.cost_price.states['readonly'] = (
+ self.cost_price.states.get('readonly', False)
+ | ((Eval('type', 'goods') == 'goods') & (Eval('id', -1) >= 0)))
+ self.cost_price.depends = copy.copy(self.cost_price.depends)
+ if 'type' not in self.cost_price.depends:
+ self.cost_price.depends.append('type')
+ self._reset_columns()
+
Template()
+
+
+class UpdateCostPriceAsk(ModelView):
+ 'Update Cost Price Ask'
+ _name = 'product.update_cost_price.ask'
+ product = fields.Many2One('product.product', 'Product', readonly=True)
+ cost_price = fields.Numeric('Cost Price', required=True, digits=(16, 4))
+
+UpdateCostPriceAsk()
+
+
+class UpdateCostPriceShowMove(ModelView):
+ 'Update Cost Price Show Move'
+ _name = 'product.update_cost_price.show_move'
+ price_difference = fields.Numeric('Price Difference', readonly=True,
+ digits=(16, 4))
+ amount = fields.Numeric('Amount', readonly=True,
+ digits=(16, Eval('currency_digits', 2)), depends=['currency_digits'])
+ currency_digits = fields.Integer('Currency Digits', readonly=True)
+ journal = fields.Many2One('account.journal', 'Journal', required=True)
+ stock_account = fields.Many2One('account.account', 'Stock Account',
+ readonly=True)
+ counterpart = fields.Many2One('account.account', 'Counterpart',
+ domain=[
+ ('company', 'in', [Get(Eval('context', {}), 'company'), False]),
+ ('id', '!=', Eval('stock_account')),
+ ],
+ depends=['company'], required=True)
+ description = fields.Char('Description', required=True)
+
+UpdateCostPriceShowMove()
+
+
+class UpdateCostPrice(Wizard):
+ 'Update Cost Price'
+ _name = 'product.update_cost_price'
+ start_state = 'ask_price'
+ ask_price = StateView('product.update_cost_price.ask',
+ 'account_stock_continental.update_cost_price_ask_form', [
+ Button('Cancel', 'end', 'tryton-cancel'),
+ Button('Ok', 'should_show_move', 'tryton-go-next', default=True),
+ ])
+ should_show_move = StateTransition()
+ show_move = StateView('product.update_cost_price.show_move',
+ 'account_stock_continental.update_cost_price_show_move_form', [
+ Button('Cancel', 'end', 'tryton-cancel'),
+ Button('Ok', 'create_move', 'tryton-ok', default=True),
+ ])
+ create_move = StateTransition()
+ update_price = StateTransition()
+
+ def __init__(self):
+ super(UpdateCostPrice, self).__init__()
+ self._error_messages.update({
+ 'same_account': 'The stock account and the counterpart can '
+ 'not be the same account',
+ })
+
+ def default_ask_price(self, session, fields):
+ if 'product' in fields:
+ return {
+ 'product': Transaction().context['active_id'],
+ }
+
+ def get_quantity(self):
+ pool = Pool()
+ date_obj = pool.get('ir.date')
+ product_obj = pool.get('product.product')
+ stock_obj = pool.get('stock.location')
+
+ locations = stock_obj.search([('type', '=', 'storage')])
+ stock_date_end = date_obj.today()
+ with Transaction().set_context(locations=locations,
+ stock_date_end=stock_date_end):
+ product = product_obj.browse(Transaction().context['active_id'])
+ if hasattr(product_obj, 'cost_price'):
+ return product.quantity
+ else:
+ return product.template.quantity
+
+ def transition_should_show_move(self, session):
+ if self.get_quantity() != 0:
+ return 'show_move'
+ return 'update_price'
+
+ def default_show_move(self, session, fields):
+ pool = Pool()
+ currency_obj = pool.get('currency.currency')
+ user_obj = pool.get('res.user')
+ accountconf_obj = pool.get('account.configuration')
+ product_obj = pool.get('product.product')
+
+ product = product_obj.browse(Transaction().context['active_id'])
+ price_diff = (session.ask_price.cost_price
+ - product.cost_price)
+ user = user_obj.browse(Transaction().user)
+ amount = currency_obj.round(user.company.currency,
+ Decimal(str(self.get_quantity())) * price_diff)
+ stock_account = product.account_stock_used.id
+ config = accountconf_obj.browse(1)
+ stock_journal = config.stock_journal.id
+ counterpart = (config.cost_price_counterpart_account.id if
+ config.cost_price_counterpart_account else None)
+ return {
+ 'journal': stock_journal,
+ 'amount': amount,
+ 'price_difference': price_diff,
+ 'stock_account': stock_account,
+ 'counterpart': counterpart,
+ 'currency_digits': user.company.currency.digits,
+ }
+
+ def get_move_lines(self, session):
+ amount = session.show_move.amount
+ return [{
+ 'name': session.ask_price.product.name,
+ 'debit': amount if amount > 0 else 0,
+ 'credit': -amount if amount < 0 else 0,
+ 'account': session.show_move.stock_account.id,
+ },
+ {
+ 'name': session.ask_price.product.name,
+ 'debit': -amount if amount < 0 else 0,
+ 'credit': amount if amount > 0 else 0,
+ 'account': session.show_move.counterpart.id,
+ },
+ ]
+
+ def get_move(self, session):
+ pool = Pool()
+ date_obj = pool.get('ir.date')
+ period_obj = pool.get('account.period')
+ user_obj = pool.get('res.user')
+
+ user = user_obj.browse(Transaction().user)
+ period_id = period_obj.find(user.company.id)
+ return {
+ 'name': session.show_move.description,
+ 'period': period_id,
+ 'journal': session.show_move.journal.id,
+ 'date': date_obj.today(),
+ 'lines': [('create', l)
+ for l in self.get_move_lines(session)],
+ }
+
+ def transition_create_move(self, session):
+ move_obj = Pool().get('account.move')
+
+ if session.show_move.counterpart == session.show_move.stock_account:
+ self.raise_user_error('same_account')
+ move_data = self.get_move(session)
+ with Transaction().set_user(0, set_context=True):
+ move_id = move_obj.create(move_data)
+ move_obj.post([move_id])
+ return 'update_price'
+
+ def transition_update_price(self, session):
+ product_obj = Pool().get('product.product')
+ product_obj.write(session.ask_price.product.id, {
+ 'cost_price': session.ask_price.cost_price,
+ })
+ return 'end'
+
+UpdateCostPrice()
diff --git a/product.xml b/product.xml
index af93dbda75..4b482aac74 100644
--- a/product.xml
+++ b/product.xml
@@ -3,6 +3,55 @@
this repository contains the full copyright notices and license terms. -->
+
+ product.update_cost_price.ask
+ form
+
+
+
+
+
+
+
+ ]]>
+
+
+
+ product.update_cost_price.show_move
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+ Update Cost Price
+ product.update_cost_price
+
+
+ form_action
+ product.product,-1
+
+
+
+
+
+
product.category
@@ -51,6 +100,5 @@ this repository contains the full copyright notices and license terms. -->
]]>
-