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) + 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 - def _price_update(self, cr, uid, quant, newprice, context=None): - self.write(cr, uid, [quant.id], {'cost': newprice}, 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, 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"