[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:
parent
5b69ce1902
commit
d538ad4f1a
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue