1
# -*- coding: utf-8 -*-
2
##############################################################################
4
# Copyright (C) 2013 Agile Business Group sagl (<http://www.agilebg.com>)
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU Affero General Public License as published
8
# by the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU Affero General Public License for more details.
16
# You should have received a copy of the GNU Affero General Public License
17
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
##############################################################################
21
from openerp.osv import fields, orm
22
from openerp.tools.translate import _
23
import openerp.addons.decimal_precision as dp
26
class stock_production_lot(orm.Model):
27
_inherit = "stock.production.lot"
30
'standard_price': fields.float(
31
'Cost', digits_compute=dp.get_precision('Lot Price'),
32
help="Cost price (in company currency) of the lot used for "
33
"standard stock valuation in accounting.",
34
groups="base.group_user"
36
'cost_method': fields.selection(
38
('standard', 'Standard Price'),
39
('average', 'Average Price')
41
help="Standard Price: The cost price is manually updated at the "
42
"end of a specific period. \nAverage Price: The cost price is "
43
"recomputed at each incoming shipment."
47
def price_get(self, cr, uid, ids, context=None):
51
product_uom_obj = self.pool.get('product.uom')
52
for lot in self.browse(cr, uid, ids, context=context):
53
res[lot.id] = lot['standard_price'] or 0.0
55
uom = lot.product_id.uom_id or lot.product_id.uos_id
56
res[lot.id] = product_uom_obj._compute_price(
58
uom.id, res[lot.id], context['uom'])
59
# Convert from price_type currency to asked one
60
if 'currency_id' in context:
62
if lot.company_id and lot.company_id.currency_id:
63
currency_id = lot.company_id.currency_id.id
65
lot.product_id.company_id
66
and lot.product_id.company_id.currency_id
68
currency_id = lot.product_id.company_id.currency_id.id
70
res[lot.id] = self.pool.get('res.currency').compute(
73
context['currency_id'], res[lot.id], context=context)
76
def do_change_standard_price(self, cr, uid, ids, datas, context=None):
77
""" Changes the Standard Price of Lot and creates an account move
79
@param datas : dict. contain default datas like new_price,
80
stock_output_account, stock_input_account, stock_journal
81
@param context: A standard dictionary
83
location_obj = self.pool.get('stock.location')
84
move_obj = self.pool.get('account.move')
85
move_line_obj = self.pool.get('account.move.line')
89
new_price = datas.get('new_price', 0.0)
90
stock_output_acc = datas.get('stock_output_account', False)
91
stock_input_acc = datas.get('stock_input_account', False)
92
journal_id = datas.get('stock_journal', False)
93
lot_obj = self.browse(cr, uid, ids, context=context)[0]
95
lot_obj.product_id.categ_id.property_stock_valuation_account_id)
96
account_valuation_id = (
97
account_valuation and account_valuation.id or False)
98
if not account_valuation_id:
101
_('Specify valuation Account for Product Category: %s.')
102
% (lot_obj.product_id.categ_id.name))
104
loc_ids = location_obj.search(
105
cr, uid, [('usage', '=', 'internal')],
108
for location in location_obj.browse(
109
cr, uid, loc_ids, context=context
113
'location_id': location.id,
114
'compute_child': False
117
lot = self.browse(cr, uid, rec_id, context=c)
118
qty = lot.stock_available
119
diff = lot.standard_price - new_price
121
raise orm.except_orm(
123
_("No difference between standard price!"
127
location.company_id and location.company_id.id or False
130
raise orm.except_orm(
132
_('Please specify company in Location.'))
136
product = lot.product_id
139
and product.categ_id.property_stock_journal
141
journal_id = product.categ_id.property_stock_journal.id
143
raise orm.except_orm(
145
_("Please define journal "
146
"on the product category: '%s' (id: %d).") %
147
(product.categ_id.name, product.categ_id.id,))
148
move_id = move_obj.create(cr, uid, {
149
'journal_id': journal_id,
150
'company_id': company_id
153
move_ids.append(move_id)
156
if not stock_input_acc:
158
product.property_stock_account_input.id
160
if not stock_input_acc:
163
property_stock_account_input_categ.id
165
if not stock_input_acc:
166
raise orm.except_orm(
168
_("Please define stock input account "
169
"for this product: '%s' (id: %d).") %
170
(product.name, product.id,))
171
amount_diff = qty * diff
172
move_line_obj.create(cr, uid, {
173
'name': product.name,
174
'account_id': stock_input_acc,
175
'debit': amount_diff,
178
move_line_obj.create(cr, uid, {
179
'name': product.categ_id.name,
180
'account_id': account_valuation_id,
181
'credit': amount_diff,
185
if not stock_output_acc:
187
product.property_stock_account_output.id
189
if not stock_output_acc:
192
property_stock_account_output_categ.id
194
if not stock_output_acc:
195
raise orm.except_orm(
197
_("Please define stock output account "
198
"for this product: '%s' (id: %d).") %
199
(product.name, product.id,))
200
amount_diff = qty * -diff
201
move_line_obj.create(cr, uid, {
202
'name': product.name,
203
'account_id': stock_output_acc,
204
'credit': amount_diff,
207
move_line_obj.create(cr, uid, {
208
'name': product.categ_id.name,
209
'account_id': account_valuation_id,
210
'debit': amount_diff,
214
self.write(cr, uid, rec_id, {'standard_price': new_price})
219
class stock_move(orm.Model):
220
_inherit = "stock.move"
222
def _get_reference_accounting_values_for_valuation(
223
self, cr, uid, move, context=None
226
stock_move, self)._get_reference_accounting_values_for_valuation(
227
cr, uid, move, context=context)
228
if move.product_id.lot_valuation and move.prodlot_id:
229
product_uom_obj = self.pool.get('product.uom')
230
qty = product_uom_obj._compute_qty(
231
cr, uid, move.product_uom.id,
232
move.product_qty, move.product_id.uom_id.id)
236
context, currency_id=move.company_id.currency_id.id)
237
amount_unit = move.prodlot_id.price_get(
238
context=currency_ctx)[move.prodlot_id.id]
239
reference_amount = amount_unit * qty
240
new_res = (reference_amount, move.company_id.currency_id.id)
244
def do_partial(self, cr, uid, ids, partial_datas, context=None):
247
pick_obj = self.pool.get('stock.picking')
248
for move in self.browse(cr, uid, ids, context=context):
249
pick_obj.write_lot(cr, uid, move, partial_datas, context=context)
250
res = super(stock_move, self).do_partial(
251
cr, uid, ids, partial_datas, context=context)
255
class stock_picking(orm.Model):
256
_inherit = "stock.picking"
258
def compute_price(self, cr, uid, partial_datas, move, context=None):
261
lot_obj = self.pool.get('stock.production.lot')
262
uom_obj = self.pool.get('product.uom')
263
move_obj = self.pool.get('stock.move')
264
currency_obj = self.pool.get('res.currency')
265
partial_data = partial_datas.get('move%s' % (move.id), {})
266
product_uom = partial_data.get('product_uom', False)
267
product_qty = partial_data.get('product_qty', 0.0)
268
product_currency = partial_data.get('product_currency', False)
269
product_price = partial_data.get('product_price', 0.0)
271
lot = lot_obj.browse(cr, uid, move.prodlot_id.id, context=context)
272
product = lot.product_id
273
move_currency_id = move.company_id.currency_id.id
274
context['currency_id'] = move_currency_id
275
qty = uom_obj._compute_qty(
276
cr, uid, product_uom, product_qty, product.uom_id.id)
278
new_price = currency_obj.compute(
279
cr, uid, product_currency,
280
move_currency_id, product_price)
281
new_price = uom_obj._compute_price(
282
cr, uid, product_uom, new_price,
284
if lot.stock_available <= 0:
285
new_std_price = new_price
287
# Get the standard price
288
amount_unit = lot.price_get(context=context)[lot.id]
290
((amount_unit * lot.stock_available)
291
+ (new_price * qty)) / (lot.stock_available + qty)
295
cr, uid, [lot.id], {'standard_price': new_std_price},
299
# Record the values that were chosen in the wizard, so they can be
300
# used for inventory valuation if real-time valuation is enabled.
301
move_obj.write(cr, uid, [move.id], {
302
'price_unit': product_price,
303
'price_currency_id': product_currency
306
def write_lot(self, cr, uid, move, partial_datas, context=None):
307
lot_obj = self.pool.get('stock.production.lot')
308
currency_obj = self.pool.get('res.currency')
309
uom_obj = self.pool.get('product.uom')
310
if partial_datas.get('move%s' % (move.id)):
311
partial_data = partial_datas.get('move%s' % (move.id), {})
312
product_price = partial_data.get('product_price', 0.0)
313
product_currency = partial_data.get('product_currency', False)
314
product_uom = partial_data.get('product_uom', False)
315
if partial_data.get('prodlot_id'):
316
lot = lot_obj.browse(
317
cr, uid, partial_data['prodlot_id'], context)
318
product = lot.product_id
320
move.product_id.lot_valuation and (
321
move.picking_id.type == 'in'
322
) and (lot.cost_method == 'average')
325
cr, uid, partial_datas, move, context=context)
327
move.product_id.lot_valuation and product_price
328
and not lot.standard_price
330
new_price = currency_obj.compute(
331
cr, uid, product_currency,
332
move.company_id.currency_id.id, product_price)
333
new_price = uom_obj._compute_price(
334
cr, uid, product_uom, new_price,
336
lot.write({'standard_price': new_price})
338
def do_partial(self, cr, uid, ids, partial_datas, context=None):
341
for pick in self.browse(cr, uid, ids, context=context):
342
for move in pick.move_lines:
343
self.write_lot(cr, uid, move, partial_datas, context=context)
344
res = super(stock_picking, self).do_partial(
345
cr, uid, ids, partial_datas, context=context)
349
class stock_partial_picking(orm.TransientModel):
350
_inherit = "stock.partial.picking"
352
def _product_cost_for_average_update(self, cr, uid, move):
354
stock_partial_picking, self
355
)._product_cost_for_average_update(cr, uid, move)
356
if move.prodlot_id and move.product_id.lot_valuation:
357
res['cost'] = move.prodlot_id.standard_price