From 9f046d538fc1a8a258591f560ec3b1b4cfd4ca72 Mon Sep 17 00:00:00 2001 From: Arnold Moyaux Date: Thu, 1 Sep 2022 12:22:11 +0000 Subject: [PATCH] [IMP] purchase_stock, stock_account: handle invoice before receipt In some buisness case when the invoice is done before the receipt, the `stock.valuation.layer` price unit will be taken on the invoice rather than the `purchase.order.line` Part-of: odoo/odoo#99411 --- addons/purchase_stock/models/stock_move.py | 48 +++++++++++++++------ addons/stock_account/models/account_move.py | 2 + 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/addons/purchase_stock/models/stock_move.py b/addons/purchase_stock/models/stock_move.py index e70323dfb34..9e7900d76b0 100644 --- a/addons/purchase_stock/models/stock_move.py +++ b/addons/purchase_stock/models/stock_move.py @@ -29,10 +29,33 @@ class StockMove(models.Model): def _get_price_unit(self): """ Returns the unit price for the move""" self.ensure_one() - if self.purchase_line_id and self.product_id.id: - price_unit_prec = self.env['decimal.precision'].precision_get('Product Price') - line = self.purchase_line_id - order = line.order_id + if not self.purchase_line_id or not self.product_id.id: + return super(StockMove, self)._get_price_unit() + price_unit_prec = self.env['decimal.precision'].precision_get('Product Price') + line = self.purchase_line_id + order = line.order_id + received_qty = line.qty_received + if self.state == 'done': + received_qty -= self.product_uom._compute_quantity(self.quantity_done, line.product_uom) + if line.qty_invoiced > received_qty: + move_layer = line.move_ids.stock_valuation_layer_ids + invoiced_layer = line.invoice_lines.stock_valuation_layer_ids + receipt_value = sum(move_layer.mapped('value')) + sum(invoiced_layer.mapped('value')) + invoiced_value = 0 + invoiced_qty = 0 + for invoice_line in line.invoice_lines: + if invoice_line.tax_ids: + invoiced_value += invoice_line.tax_ids.with_context(round=False).compute_all( + invoice_line.price_unit, currency=invoice_line.account_id.currency_id, quantity=invoice_line.quantity)['total_void'] + else: + invoiced_value += invoice_line.price_unit * invoice_line.quantity + invoiced_qty += invoice_line.product_uom_id._compute_quantity(invoice_line.quantity, line.product_id.uom_id) + # TODO currency check + remaining_value = invoiced_value - receipt_value + # TODO qty_received in product uom + remaining_qty = invoiced_qty - line.product_uom._compute_quantity(received_qty, line.product_id.uom_id) + price_unit = float_round(remaining_value / remaining_qty, precision_digits=price_unit_prec) + else: price_unit = line.price_unit if line.taxes_id: qty = line.product_qty or 1 @@ -40,15 +63,14 @@ class StockMove(models.Model): price_unit = float_round(price_unit / qty, precision_digits=price_unit_prec) if line.product_uom.id != line.product_id.uom_id.id: price_unit *= line.product_uom.factor / line.product_id.uom_id.factor - if order.currency_id != order.company_id.currency_id: - # The date must be today, and not the date of the move since the move move is still - # in assigned state. However, the move date is the scheduled date until move is - # done, then date of actual move processing. See: - # https://github.com/odoo/odoo/blob/2f789b6863407e63f90b3a2d4cc3be09815f7002/addons/stock/models/stock_move.py#L36 - price_unit = order.currency_id._convert( - price_unit, order.company_id.currency_id, order.company_id, fields.Date.context_today(self), round=False) - return price_unit - return super(StockMove, self)._get_price_unit() + if order.currency_id != order.company_id.currency_id: + # The date must be today, and not the date of the move since the move move is still + # in assigned state. However, the move date is the scheduled date until move is + # done, then date of actual move processing. See: + # https://github.com/odoo/odoo/blob/2f789b6863407e63f90b3a2d4cc3be09815f7002/addons/stock/models/stock_move.py#L36 + price_unit = order.currency_id._convert( + price_unit, order.company_id.currency_id, order.company_id, fields.Date.context_today(self), round=False) + return price_unit def _generate_valuation_lines_data(self, partner_id, qty, debit_value, credit_value, debit_account_id, credit_account_id, svl_id, description): """ Overridden from stock_account to support amount_currency on valuation lines generated from po diff --git a/addons/stock_account/models/account_move.py b/addons/stock_account/models/account_move.py index 690bb3ca247..4d8d332c646 100644 --- a/addons/stock_account/models/account_move.py +++ b/addons/stock_account/models/account_move.py @@ -247,6 +247,8 @@ class AccountMove(models.Model): class AccountMoveLine(models.Model): _inherit = 'account.move.line' + stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'account_move_line_id', string='Stock Valuation Layer') + def _compute_account_id(self): super()._compute_account_id() input_lines = self.filtered(lambda line: (