[IMP] Add test purchase order other company to tests, add price_unit_out for generating accounting entries by stock move matching, change demo data where internal shippings becomes transit location

bzr revid: jco@openerp.com-20130507140443-6z4wzpnac62911ku
This commit is contained in:
Josse Colpaert 2013-05-07 16:04:43 +02:00
parent 5b69ce1902
commit d538ad4f1a
5 changed files with 138 additions and 81 deletions

View File

@ -216,7 +216,10 @@ class product_product(osv.osv):
if type(context['location']) == type(1):
location_ids = [context['location']]
elif type(context['location']) in (type(''), type(u'')):
location_ids = location_obj.search(cr, uid, [('name','ilike',context['location'])], context=context)
if context.get('force_company', False):
location_ids = location_obj.search(cr, uid, [('name','ilike',context['location']), ('company_id', '=', context['force_company'])], context=context)
else:
location_ids = location_obj.search(cr, uid, [('name','ilike',context['location'])], context=context)
else:
location_ids = context['location']
else:
@ -225,13 +228,19 @@ class product_product(osv.osv):
if not wids:
return False
for w in warehouse_obj.browse(cr, uid, wids, context=context):
location_ids.append(w.lot_stock_id.id)
if not context.get('force_company', False) or w.lot_stock_id.company_id == context['force_company']:
location_ids.append(w.lot_stock_id.id)
# build the list of ids of children of the location given by id
if context.get('compute_child',True):
child_location_ids = location_obj.search(cr, uid, [('location_id', 'child_of', location_ids)])
if context.get('force_company', False):
child_location_ids = location_obj.search(cr, uid, [('location_id', 'child_of', location_ids), ('company_id', '=', context['force_company'])])
else:
child_location_ids = location_obj.search(cr, uid, [('location_id', 'child_of', location_ids)])
location_ids = child_location_ids or location_ids
return location_ids
@ -299,12 +308,6 @@ class product_product(osv.osv):
if where_add:
where += where_add
#It depends on the company of the user OR by using force_company in context
user = self.pool.get("res.users").browse(cr, uid, uid, context=context)
if context.get("force_company", False):
where.append(context['force_company'])
else:
where.append(user.company_id.id)
prodlot_id = context.get('prodlot_id', False)
prodlot_clause = ''
@ -322,7 +325,6 @@ class product_product(osv.osv):
'and location_dest_id IN %s '\
'and product_id IN %s '\
'and state IN %s ' + (date_str and 'and '+date_str+' ' or '') +' '\
'and company_id = %s '\
+ prodlot_clause +
'group by product_id,product_uom',tuple(where))
results = cr.fetchall()
@ -335,7 +337,6 @@ class product_product(osv.osv):
'and location_dest_id NOT IN %s '\
'and product_id IN %s '\
'and state in %s ' + (date_str and 'and '+date_str+' ' or '') + ' '\
'and company_id = %s '\
+ prodlot_clause +
'group by product_id,product_uom',tuple(where))
results2 = cr.fetchall()

View File

@ -2293,6 +2293,9 @@ class stock_move(osv.osv):
return reference_amount, reference_currency_id
def _create_product_valuation_moves(self, cr, uid, move, context=None):
"""
Generate the appropriate accounting moves if the product being moves is subject
@ -2316,9 +2319,9 @@ class stock_move(osv.osv):
reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, src_company_ctx)
#returning goods to supplier
if move.location_dest_id.usage == 'supplier':
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_src, reference_amount, reference_currency_id, context))]
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_src, reference_amount, reference_currency_id, 'out', context=context))]
else:
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_dest, reference_amount, reference_currency_id, context))]
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_dest, reference_amount, reference_currency_id, 'out', context=context))]
# Incoming moves (or cross-company input part)
if move.location_dest_id.company_id \
@ -2328,9 +2331,9 @@ class stock_move(osv.osv):
reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, src_company_ctx)
#goods return from customer
if move.location_id.usage == 'customer':
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_dest, acc_valuation, reference_amount, reference_currency_id, context))]
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_dest, acc_valuation, reference_amount, reference_currency_id, 'in', context=context))]
else:
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_src, acc_valuation, reference_amount, reference_currency_id, context))]
account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_src, acc_valuation, reference_amount, reference_currency_id, 'in', context=context))]
move_obj = self.pool.get('account.move')
for j_id, move_lines in account_moves:
move_obj.create(cr, uid,
@ -2394,55 +2397,70 @@ class stock_move(osv.osv):
return True
def _create_account_move_line(self, cr, uid, move, src_account_id, dest_account_id, reference_amount, reference_currency_id, context=None):
def _create_account_move_line(self, cr, uid, move, src_account_id, dest_account_id, reference_amount, reference_currency_id, type='', context=None):
"""
Generate the account.move.line values to post to track the stock valuation difference due to the
processing of the given stock move.
"""
# prepare default values considering that the destination accounts have the reference_currency_id as their main currency
partner_id = (move.picking_id.partner_id and self.pool.get('res.partner')._find_accounting_partner(move.picking_id.partner_id).id) or False
debit_line_vals = {
'name': move.name,
'product_id': move.product_id and move.product_id.id or False,
'quantity': move.product_qty,
'ref': move.picking_id and move.picking_id.name or False,
'date': time.strftime('%Y-%m-%d'),
'partner_id': partner_id,
'debit': reference_amount,
'account_id': dest_account_id,
}
credit_line_vals = {
'name': move.name,
'product_id': move.product_id and move.product_id.id or False,
'quantity': move.product_qty,
'ref': move.picking_id and move.picking_id.name or False,
'date': time.strftime('%Y-%m-%d'),
'partner_id': partner_id,
'credit': reference_amount,
'account_id': src_account_id,
}
move_list = []
# Consists of access rights
# TODO Check if currency is not needed
if type == 'out' and move.product_id.cost_method in ['fifo', 'lifo']:
match_obj = self.pool.get("stock.move.matching")
matches = match_obj.search(cr, uid, [('move_out_id','=', move.id)], context=context)
for match in match_obj.browse(cr, uid, matches, context=context):
move_in = match.move_in_id
move_list += [(match.qty, match.qty * match.price_unit_out)]
else:
move_list = [(move.product_qty, reference_amount)]
res = []
for item in move_list:
# prepare default values considering that the destination accounts have the reference_currency_id as their main currency
partner_id = (move.picking_id.partner_id and self.pool.get('res.partner')._find_accounting_partner(move.picking_id.partner_id).id) or False
debit_line_vals = {
'name': move.name,
'product_id': move.product_id and move.product_id.id or False,
'quantity': item[0],
'ref': move.picking_id and move.picking_id.name or False,
'date': time.strftime('%Y-%m-%d'),
'partner_id': partner_id,
'debit': item[1],
'account_id': dest_account_id,
}
credit_line_vals = {
'name': move.name,
'product_id': move.product_id and move.product_id.id or False,
'quantity': item[0],
'ref': move.picking_id and move.picking_id.name or False,
'date': time.strftime('%Y-%m-%d'),
'partner_id': partner_id,
'credit': item[1],
'account_id': src_account_id,
}
# if we are posting to accounts in a different currency, provide correct values in both currencies correctly
# when compatible with the optional secondary currency on the account.
# Financial Accounts only accept amounts in secondary currencies if there's no secondary currency on the account
# or if it's the same as that of the secondary amount being posted.
account_obj = self.pool.get('account.account')
src_acct, dest_acct = account_obj.browse(cr, uid, [src_account_id, dest_account_id], context=context)
src_main_currency_id = src_acct.company_id.currency_id.id
dest_main_currency_id = dest_acct.company_id.currency_id.id
cur_obj = self.pool.get('res.currency')
if reference_currency_id != src_main_currency_id:
# fix credit line:
credit_line_vals['credit'] = cur_obj.compute(cr, uid, reference_currency_id, src_main_currency_id, reference_amount, context=context)
if (not src_acct.currency_id) or src_acct.currency_id.id == reference_currency_id:
credit_line_vals.update(currency_id=reference_currency_id, amount_currency=-reference_amount)
if reference_currency_id != dest_main_currency_id:
# fix debit line:
debit_line_vals['debit'] = cur_obj.compute(cr, uid, reference_currency_id, dest_main_currency_id, reference_amount, context=context)
if (not dest_acct.currency_id) or dest_acct.currency_id.id == reference_currency_id:
debit_line_vals.update(currency_id=reference_currency_id, amount_currency=reference_amount)
return [(0, 0, debit_line_vals), (0, 0, credit_line_vals)]
# if we are posting to accounts in a different currency, provide correct values in both currencies correctly
# when compatible with the optional secondary currency on the account.
# Financial Accounts only accept amounts in secondary currencies if there's no secondary currency on the account
# or if it's the same as that of the secondary amount being posted.
#TODO -> might need to be changed still for fifolifo
account_obj = self.pool.get('account.account')
src_acct, dest_acct = account_obj.browse(cr, uid, [src_account_id, dest_account_id], context=context)
src_main_currency_id = src_acct.company_id.currency_id.id
dest_main_currency_id = dest_acct.company_id.currency_id.id
cur_obj = self.pool.get('res.currency')
if reference_currency_id != src_main_currency_id:
# fix credit line:
credit_line_vals['credit'] = cur_obj.compute(cr, uid, reference_currency_id, src_main_currency_id, reference_amount, context=context)
if (not src_acct.currency_id) or src_acct.currency_id.id == reference_currency_id:
credit_line_vals.update(currency_id=reference_currency_id, amount_currency=-reference_amount)
if reference_currency_id != dest_main_currency_id:
# fix debit line:
debit_line_vals['debit'] = cur_obj.compute(cr, uid, reference_currency_id, dest_main_currency_id, reference_amount, context=context)
if (not dest_acct.currency_id) or dest_acct.currency_id.id == reference_currency_id:
debit_line_vals.update(currency_id=reference_currency_id, amount_currency=reference_amount)
res += [(0, 0, debit_line_vals), (0, 0, credit_line_vals)]
return res
def unlink(self, cr, uid, ids, context=None):
if context is None:
@ -2666,7 +2684,7 @@ class stock_move(osv.osv):
if avg_in_update or avg_out_update:
# If no price from picking, use cost price from product
if product_price == 0:
if product_price == 0.0:
product_price = product.price_get('standard_price', context=ctx)[product.id]
move_currency_id = move.company_id.currency_id.id

View File

@ -259,7 +259,7 @@
<record id="stock_location_intermediatelocation0" model="stock.location">
<field name="partner_id" ref="base.main_partner"/>
<field name="location_id" ref="stock.stock_location_locations_partner"/>
<field name="usage">procurement</field>
<field name="usage">transit</field>
<field name="name">Internal Shippings</field>
</record>

View File

@ -141,31 +141,35 @@ class stock_move(osv.osv):
ctx['force_company'] = company_id
product = product_obj.browse(cr, uid, move.product_id.id, context=ctx)
cost_method = product.cost_method
uom_id = product.uom_id.id
if move.picking_id.type == 'out' and cost_method in ['fifo', 'lifo']:
#This price has to be put as the new standard price for the product, but needs to be converted to product UoM and currency
#convert uom of qty
product_uom_qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, uom_id)
#get_stock_matchings will convert to currency and UoM of this stock move
tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], product_qty, cost_method == 'fifo',
product_uom, move.company_id.currency_id.id, context=context) #Always move of the company
product_uom, move.company_id.currency_id.id, context=context) #Always currency of the company
price_amount = 0.0
amount = 0.0
move_currency_id = move.company_id.currency_id.id
ctx['currency_id'] = move_currency_id
for match in tuples:
matchvals = {'move_in_id': match[0], 'qty': match[1],
'move_out_id': move.id}
'move_out_id': move.id, 'price_unit_out': match[2]}
match_id = matching_obj.create(cr, uid, matchvals, context=context)
move_in = self.browse(cr, uid, match[0], context=context)
#Reduce remaining quantity
self.write(cr, uid, match[0], { 'qty_remaining': move_in.qty_remaining - match[3]}, context=context)
price_amount += match[1] * match[2]
amount += match[1]
self.write(cr, uid, move.id, {'price_unit': price_amount / amount}, context=context)
print price_amount
print amount
#This price has to be put as the new standard price for the product, but needs to be converted to product UoM and currency
#convert uom of qty
uom_id = product.uom_id.id
product_qty = uom_obj._compute_qty(cr, uid, product_uom, amount, uom_id)
if product.qty_available >= product_uom_qty:
self.write(cr, uid, move.id, {'price_unit': price_amount / amount}, context=context)
else:
self.write(cr, uid, move.id, {'price_unit': price_amount / amount}, context=context)
#convert price, no need of UoM conversion as it is the total price
currency_id = move.company_id.currency_id.id
currency_from = move.price_currency_id
@ -175,16 +179,23 @@ class stock_move(osv.osv):
else:
new_price = price_amount
#new_price does not depend on qty as it is the total amount => no conversion needed for uom
product_obj.write(cr, uid, product.id, {'standard_price': new_price / product_qty}, context=ctx)
# When the move is products returned to supplier or return products from customer
# then the price should be the price from the original move
product_obj.write(cr, uid, product.id, {'standard_price': new_price / product_uom_qty}, context=ctx)
# When the move is products returned to supplier or return products from customer,
# it should be treated as a normal in or out, so for every in
elif cost_method in ['fifo', 'lifo']:
#The currency in the stock move should be the currency of the company
if product_currency != move.company_id.currency_id.id:
new_price = currency_obj.compute(cr, uid, product_currency, move.company_id.currency_id.id,
product_price, round=False)
else:
new_price = product_price
if product_price > 0.0:
if product_currency != move.company_id.currency_id.id:
new_price = currency_obj.compute(cr, uid, product_currency, move.company_id.currency_id.id,
product_price, round=False)
else:
new_price = product_price
else:
if product_uom != uom_id:
new_price = uom_obj._compute_price(cr, uid, uom_id, new_price,
product_uom)
else:
new_price = product.standard_price
self.write(cr, uid, [move.id],
{'price_unit': new_price,
'price_currency_id': move.company_id.currency_id.id})
@ -196,7 +207,8 @@ class stock_move_matching(osv.osv):
_columns = {
'move_in_id': fields.many2one('stock.move', 'Stock move in', required=True),
'move_out_id': fields.many2one('stock.move', 'Stock move out', required=True),
'qty': fields.integer('Quantity', required=True),
'qty': fields.float('Quantity', required=True),
'price_unit':fields.related('move_in_id', 'price_unit', string="Unit price", type="float"),
'price_unit_out': fields.float('Unit price out')
}

View File

@ -74,6 +74,31 @@
pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo2")).picking_ids
partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
self.do_partial(cr, uid, [partial_id])
-
A purchase order towards the Chicago shop
-
!record {model: purchase.order, id: purchase_order_fifo_comp}:
partner_id: base.res_partner_3
company_id: stock.res_company_1
location_id: stock.stock_location_shop0
pricelist_id: 1
order_line:
- product_id: product_fifo_icecream
product_qty: 35.0
product_uom: product.product_uom_categ_kgm
price_unit: 50.0
name: 'FIFO Ice Cream'
-
I confirm the Chicago Shop company's purchase order'
-
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_fifo_comp}
-
I receive the Chicago Shop company's purchase order'
-
!python {model: stock.partial.picking}: |
pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo_comp")).picking_ids
partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
self.do_partial(cr, uid, [partial_id])
-
Check the standard price should not have changed
-
@ -252,6 +277,7 @@
!python {model: product.product}: |
print self.browse(cr, uid, ref("product_fifo_icecream")).standard_price
print self.browse(cr, uid, ref("product_fifo_icecream")).qty_available
print self.browse(cr, uid, ref("product_fifo_icecream"), context={'force_company': 1}).qty_available
list = self.pool.get("stock.move").search(cr, uid, [('product_id','=', ref("product_fifo_icecream"))])
for move in self.pool.get("stock.move").browse(cr, uid, list):
print move.price_unit, move.product_qty, move.qty_remaining, move.type, move.date