diff --git a/addons/purchase_stock/models/stock_move.py b/addons/purchase_stock/models/stock_move.py index 9f9f02cf0ba..e5a6710feaa 100644 --- a/addons/purchase_stock/models/stock_move.py +++ b/addons/purchase_stock/models/stock_move.py @@ -45,13 +45,20 @@ class StockMove(models.Model): if float_compare(line.qty_invoiced, received_qty, precision_rounding=line.product_uom.rounding) > 0: 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')) + # value on valuation layer is in company's currency, while value on invoice line is in order's currency + receipt_value = 0 + if move_layer: + receipt_value += sum(move_layer.mapped(lambda l: l.currency_id._convert( + l.value, order.currency_id, order.company_id, l.account_move_id.date, round=False))) + if invoiced_layer: + receipt_value += sum(invoiced_layer.mapped(lambda l: l.currency_id._convert( + l.value, order.currency_id, order.company_id, l.account_move_id.date, round=False))) 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'] + invoice_line.price_unit, currency=invoice_line.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) diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py index 8a141046c73..c89f79e7902 100644 --- a/addons/purchase_stock/tests/test_stockvaluation.py +++ b/addons/purchase_stock/tests/test_stockvaluation.py @@ -1887,3 +1887,48 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): full_reconcile = input_amls[0].full_reconcile_id self.assertTrue(full_reconcile) self.assertTrue(all(aml.full_reconcile_id == full_reconcile for aml in input_amls)) + + def test_invoice_on_ordered_qty_with_backorder_and_different_currency(self): + """Create a PO with currency different from the company currency. Set the + product to be invoiced on ordered quantities. Receive partially the products + and create a backorder. Create an invoice for the ordered quantity. Then + receive the backorder. Check if the valuation layer is correctly created. + """ + usd_currency = self.env.ref('base.USD') + self.env.company.currency_id = usd_currency.id + self.product1.categ_id.property_cost_method = 'fifo' + self.product1.purchase_method = 'purchase' + + price_unit_EUR = 100 + price_unit_USD = self.env.ref('base.EUR')._convert(price_unit_EUR, usd_currency, self.env.company, fields.Date.today(), round=False) + po = self.env['purchase.order'].create({ + 'partner_id': self.partner_id.id, + 'currency_id': self.env.ref('base.EUR').id, + 'order_line': [ + (0, 0, { + 'name': self.product1.name, + 'product_id': self.product1.id, + 'product_qty': 12.0, + 'product_uom': self.product1.uom_po_id.id, + 'price_unit': 100.0, + 'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT), + }), + ], + }) + po.button_confirm() + picking = po.picking_ids[0] + move = picking.move_ids[0] + move.quantity_done = 10 + res_dict = picking.button_validate() + self.assertEqual(res_dict['res_model'], 'stock.backorder.confirmation') + wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id')).with_context(res_dict['context']) + wizard.process() + self.assertAlmostEqual(move.stock_valuation_layer_ids.unit_cost, price_unit_USD) + + po.action_create_invoice() + + picking2 = po.picking_ids.filtered(lambda p: p.backorder_id) + move2 = picking2.move_ids[0] + move2.quantity_done = 2 + picking2.button_validate() + self.assertAlmostEqual(move2.stock_valuation_layer_ids.unit_cost, price_unit_USD)