summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin (OpenERP) <qdp-launchpad@openerp.com>2013-09-23 16:33:09 +0200
committerQuentin (OpenERP) <qdp-launchpad@openerp.com>2013-09-23 16:33:09 +0200
commit4bea4bc1f33cd5d4a6300fcde2b6bebe405d5cff (patch)
treeb5c4acdf74f8f22309f45ece6d5894e9460999be
parentba60391f0725af2e46e6cb972750eff3b1793928 (diff)
[FIX] negative quants fixing
bzr revid: qdp-launchpad@openerp.com-20130923143309-42mo2trr8jy6m5qk
-rw-r--r--addons/stock/stock.py77
-rw-r--r--addons/stock_account/stock_account.py69
2 files changed, 98 insertions, 48 deletions
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index b5bfd103141..ac47e838440 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -215,7 +215,10 @@ class stock_quant(osv.osv):
# add location_dest_id in parameters (False=use the destination of the move)
def quants_move(self, cr, uid, quants, move, context=None):
for quant, qty in quants:
- self.move_single_quant(cr, uid, quant, qty, move, context=context)
+ #quant may be a browse record or None
+ quant_record = self.move_single_quant(cr, uid, quant, qty, move, context=context)
+ #quant_record is the quant newly created or already split
+ self._quant_reconcile_negative(cr, uid, quant_record, context=context)
def check_preferred_location(self, cr, uid, move, context=None):
return move.location_dest_id
@@ -233,7 +236,6 @@ class stock_quant(osv.osv):
'history_ids': [(4, move.id)]
})
quant.refresh()
- self._quant_reconcile_negative(cr, uid, quant, context=context)
return quant
def quants_get(self, cr, uid, location, product, qty, domain=None, prefered_order=False, reservedcontext=None, restrict_lot_id=False, restrict_partner_id=False, context=None):
@@ -317,19 +319,28 @@ class stock_quant(osv.osv):
move = m
return move
- def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
- move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
- remaining_solving_quant = self._quant_split(cr, uid, quant, qty, context=context)
- remaining_to_solve_quant = self._quant_split(cr, uid, to_solve_quant, qty, context=context)
- remaining_neg_quant = self._quant_split(cr, uid, quant_neg, -qty, context=context)
- #if the reconciliation was not complete, we need to link together the remaining parts
- if remaining_to_solve_quant and remaining_neg_quant:
- self.write(cr, uid, remaining_to_solve_quant.id, {'propagated_from_id': remaining_neg_quant.id}, context=context)
- #delete the reconciled quants, as it is replaced by the solving quant
- self.unlink(cr, SUPERUSER_ID, [quant_neg.id, to_solve_quant.id], context=context)
- #call move_single_quant to ensure recursivity if necessary and do the stock valuation
- self.move_single_quant(cr, uid, quant, qty, move, context=context)
- return remaining_solving_quant, remaining_to_solve_quant
+ #def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
+ # move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
+ # remaining_solving_quant = self._quant_split(cr, uid, quant, qty, context=context)
+ # remaining_to_solve_quant = self._quant_split(cr, uid, to_solve_quant, qty, context=context)
+ # remaining_neg_quant = self._quant_split(cr, uid, quant_neg, -qty, context=context)
+ # #if the reconciliation was not complete, we need to link together the remaining parts
+ # if remaining_to_solve_quant and remaining_neg_quant:
+ # self.write(cr, uid, remaining_to_solve_quant.id, {'propagated_from_id': remaining_neg_quant.id}, context=context)
+ # #delete the reconciled quants, as it is replaced by the solving quant
+ # if remaining_neg_quant:
+ # otherquant_ids = self.search(cr, uid, [('propagated_from_id', '=', quant_neg.id)], context=context)
+ # self.write(cr, uid, otherquant_ids, {'propagated_from_id': remaining_neg_quant.id}, context=context)
+ # self.unlink(cr, SUPERUSER_ID, [quant_neg.id, to_solve_quant.id], context=context)
+ # #call move_single_quant to ensure recursivity if necessary and do the stock valuation
+ # self.move_single_quant(cr, uid, quant, qty, move, context=context)
+ # return remaining_solving_quant, remaining_to_solve_quant
+
+ def _quants_merge(self, cr, uid, solved_quant_ids, solving_quant, context=None):
+ path = []
+ for move in solving_quant.history_ids:
+ path.append((4, move.id))
+ self.write(cr, uid, solved_quant_ids, {'history_ids': path}, context=context)
def _quant_reconcile_negative(self, cr, uid, quant, context=None):
"""
@@ -344,14 +355,36 @@ class stock_quant(osv.osv):
for quant_neg, qty in quants:
if not quant_neg:
continue
- to_solve_quant = self.search(cr, uid, [('propagated_from_id', '=', quant_neg.id), ('id', '!=', solving_quant.id)], context=context)
- if not to_solve_quant:
+ to_solve_quant_ids = self.search(cr, uid, [('propagated_from_id', '=', quant_neg.id)], context=context)
+ if not to_solve_quant_ids:
continue
- to_solve_quant = self.browse(cr, uid, to_solve_quant[0], context=context)
- solving_quant, dummy = self._reconcile_single_negative_quant(cr, uid, to_solve_quant, solving_quant, quant_neg, qty, context=context)
-
- def _price_update(self, cr, uid, quant, newprice, context=None):
- self.write(cr, uid, [quant.id], {'cost': newprice}, context=context)
+ solving_qty = qty
+ solved_quant_ids = []
+ for to_solve_quant in self.browse(cr, uid, to_solve_quant_ids, context=context):
+ if solving_qty <= 0:
+ continue
+ solved_quant_ids.append(to_solve_quant.id)
+ self._quant_split(cr, uid, to_solve_quant, min(solving_qty, to_solve_quant.qty), context=context)
+ solving_qty -= min(solving_qty, to_solve_quant.qty)
+ #merge history (and cost?)
+ self._quants_merge(cr, uid, solved_quant_ids, solving_quant, context=context)
+ remaining_solving_quant = self._quant_split(cr, uid, solving_quant, qty, context=context)
+ remaining_neg_quant = self._quant_split(cr, uid, quant_neg, -qty, context=context)
+ #if the reconciliation was not complete, we need to link together the remaining parts
+ if remaining_neg_quant:
+ remaining_to_solve_quant_ids = self.search(cr, uid, [('propagated_from_id', '=', quant_neg.id), ('id', 'not in', solved_quant_ids)], context=context)
+ if remaining_to_solve_quant_ids:
+ self.write(cr, uid, remaining_to_solve_quant_ids, {'propagated_from_id': remaining_neg_quant.id}, context=context)
+ #price update + accounting entries adjustments
+ self._price_update(cr, uid, solved_quant_ids, solving_quant.cost, context=context)
+ #delete the reconciled quants, as it is replaced by the solving quant
+ self.unlink(cr, SUPERUSER_ID, [quant_neg.id, solving_quant.id], context=context)
+ solving_quant = remaining_solving_quant
+
+ #solving_quant, dummy = self._reconcile_single_negative_quant(cr, uid, to_solve_quant, solving_quant, quant_neg, qty, context=context)
+
+ def _price_update(self, cr, uid, ids, newprice, context=None):
+ self.write(cr, uid, ids, {'cost': newprice}, context=context)
def write(self, cr, uid, ids, vals, context=None):
#We want to trigger the move with nothing on reserved_quant_ids for the store of the remaining quantity
diff --git a/addons/stock_account/stock_account.py b/addons/stock_account/stock_account.py
index 713d3aeaf49..c29401d3ee2 100644
--- a/addons/stock_account/stock_account.py
+++ b/addons/stock_account/stock_account.py
@@ -59,27 +59,41 @@ class stock_quant(osv.osv):
return line.cost * line.qty
return super(stock_quant, self)._get_inventory_value(cr, uid, line, prodbrow, context=context)
- # FP Note: this is where we should post accounting entries for adjustment
- def _price_update(self, cr, uid, quant, newprice, context=None):
- super(stock_quant, self)._price_update(cr, uid, quant, newprice, context=context)
- # TODO: generate accounting entries
+ def _price_update(self, cr, uid, quant_ids, newprice, context=None):
+ if context is None:
+ context = {}
+ ctx = context.copy()
+ for quant in self.browse(cr, uid, quant_ids, context=context):
+ move = self._get_latest_move(cr, uid, quant, context=context)
+ ctx['force_valuation_amount'] = newprice - quant.cost
+ # this is where we post accounting entries for adjustment
+ self._account_entry_move(cr, uid, quant, move, context=ctx)
+ #update the standard price of the product, only if we would have done it if we'd have had enough stock at first, which means
+ #1) the product cost's method is 'real'
+ #2) we just fixed a negative quant caused by an outgoing shipment
+ if not quant.product_id.cost_method == 'real' and quant.location_id.usage != 'internal':
+ self.pool.get('stock.move')._store_average_cost_price(cr, uid, move, context=context)
+ super(stock_quant, self)._price_update(cr, uid, quant_ids, newprice, context=context)
"""
Accounting Valuation Entries
location_from: can be None if it's a new quant
"""
- def _account_entry_move(self, cr, uid, quant, location_from, location_to, move, context=None):
+ def _account_entry_move(self, cr, uid, quant, move, context=None):
+ location_from = move.location_id
+ location_to = move.location_dest_id
if context is None:
context = {}
if quant.product_id.valuation != 'real_time':
return False
- if quant.lot_id and quant.lot_id.partner_id:
+ if quant.owner_id:
#if the quant isn't owned by the company, we don't make any valuation entry
return False
- if quant.qty <= 0 or quant.propagated_from_id:
- #we don't make any stock valuation for negative quants because we may not know the real cost price.
- #The valuation will be made at the time of the reconciliation of the negative quant.
+ if quant.qty <= 0:
+ #we don't make any stock valuation for negative quants because the valuation is already made for the counterpart.
+ #At that time the valuation will be made at the product cost price and afterward there will be new accounting entries
+ #to make the adjustments when we know the real cost price.
return False
company_from = self._location_owner(cr, uid, quant, location_from, context=context)
company_to = self._location_owner(cr, uid, quant, location_to, context=context)
@@ -109,11 +123,9 @@ class stock_quant(osv.osv):
self._create_account_move_line(cr, uid, quant, move, acc_valuation, acc_dest, journal_id, context=ctx)
def move_single_quant(self, cr, uid, quant, qty, move, context=None):
- location_from = quant and quant.location_id or False
- quant = super(stock_quant, self).move_single_quant(cr, uid, quant, qty, move, context=context)
- quant.refresh()
- self._account_entry_move(cr, uid, quant, location_from, quant.location_id, move, context=context)
- return quant
+ quant_record = super(stock_quant, self).move_single_quant(cr, uid, quant, qty, move, context=context)
+ self._account_entry_move(cr, uid, quant_record, move, context=context)
+ return quant_record
def _get_accounting_data_for_valuation(self, cr, uid, move, context=None):
"""
@@ -153,7 +165,12 @@ class stock_quant(osv.osv):
Generate the account.move.line values to post to track the stock valuation difference due to the
processing of the given quant.
"""
- valuation_amount = quant.product_id.cost_method == 'real' and quant.cost or quant.product_id.standard_price
+ if context is None:
+ context = {}
+ if context.get('force_valuation_amount'):
+ valuation_amount = context.get('force_valuation_amount')
+ else:
+ valuation_amount = quant.product_id.cost_method == 'real' and quant.cost or quant.product_id.standard_price
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,
@@ -187,17 +204,17 @@ class stock_quant(osv.osv):
'line_id': move_lines,
'ref': move.picking_id and move.picking_id.name}, context=context)
- def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
- move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
- quant_neg_position = quant_neg.negative_dest_location_id.usage
- remaining_solving_quant, remaining_to_solve_quant = super(stock_quant, self)._reconcile_single_negative_quant(cr, uid, to_solve_quant, quant, quant_neg, qty, context=context)
- #update the standard price of the product, only if we would have done it if we'd have had enough stock at first, which means
- #1) there isn't any negative quant anymore
- #2) the product cost's method is 'real'
- #3) we just fixed a negative quant caused by an outgoing shipment
- if not remaining_to_solve_quant and move.product_id.cost_method == 'real' and quant_neg_position != 'internal':
- self.pool.get('stock.move')._store_average_cost_price(cr, uid, move, context=context)
- return remaining_solving_quant, remaining_to_solve_quant
+ #def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
+ # move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
+ # quant_neg_position = quant_neg.negative_dest_location_id.usage
+ # remaining_solving_quant, remaining_to_solve_quant = super(stock_quant, self)._reconcile_single_negative_quant(cr, uid, to_solve_quant, quant, quant_neg, qty, context=context)
+ # #update the standard price of the product, only if we would have done it if we'd have had enough stock at first, which means
+ # #1) there isn't any negative quant anymore
+ # #2) the product cost's method is 'real'
+ # #3) we just fixed a negative quant caused by an outgoing shipment
+ # if not remaining_to_solve_quant and move.product_id.cost_method == 'real' and quant_neg_position != 'internal':
+ # self.pool.get('stock.move')._store_average_cost_price(cr, uid, move, context=context)
+ # return remaining_solving_quant, remaining_to_solve_quant
class stock_move(osv.osv):
_inherit = "stock.move"