From c0ccf6f103a4744daeaf248feb1caf2c2745f1fa Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Thu, 12 Mar 2020 07:50:42 +0000 Subject: [PATCH] [FIX] purchase_stock, stock_landed_costs: bill after LC 1. Create a product with a category AVCO + Automated and set a price difference account 2. Create a Purchase Order for 1 unit at a value of 1000, 3. Stock entry at receipt D C Stock interim received 1000 Stock valuation 1000 4. Create a vendor bill for a Landed cost, post it D C Stock interim received 100 5. Create the landed cost from the bill and apply it on the receipt of point 3 D C Stock valuation 100 Stock interim received 100 6. Create the vendor bill for the initial PO Current entry is not correct: D C Stock interim received 1000 Price difference account 100 --> Shouldn't take place Stock interim received 100 --> Shouldn't take place This happens because the valuation layers of the landed cost are taken into account when computing the unit price of the product. This shouldn't be the case: when computing the price difference between the invoice price and the stock move price, LC should be filtered out. opw-2183511 closes odoo/odoo#47804 X-original-commit: 9bd3feb7f8778ba65e1974ef012ca3a4608878b1 Signed-off-by: Nicolas Martinelli (nim) --- .../purchase_stock/models/account_invoice.py | 5 +- .../tests/test_stock_landed_costs_purchase.py | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/addons/purchase_stock/models/account_invoice.py b/addons/purchase_stock/models/account_invoice.py index 18eb4d96935..0caa870b315 100644 --- a/addons/purchase_stock/models/account_invoice.py +++ b/addons/purchase_stock/models/account_invoice.py @@ -74,8 +74,9 @@ class AccountMove(models.Model): # In case val_stock_move is a return move, its valuation entries have been made with the # currency rate corresponding to the original stock move valuation_date = val_stock_move.origin_returned_move_id.date or val_stock_move.date - layers_qty = sum(val_stock_move.mapped('stock_valuation_layer_ids.quantity')) - layers_values = sum(val_stock_move.mapped('stock_valuation_layer_ids.value')) + svl = val_stock_move.mapped('stock_valuation_layer_ids').filtered(lambda l: l.quantity) + layers_qty = sum(svl.mapped('quantity')) + layers_values = sum(svl.mapped('value')) valuation_price_unit_total += line.company_currency_id._convert( layers_values, move.currency_id, move.company_id, valuation_date, round=False, diff --git a/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py b/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py index 8102e359c2f..47e5e8b188d 100644 --- a/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py +++ b/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import unittest from odoo.addons.stock_landed_costs.tests.common import TestStockLandedCostsCommon +from odoo.addons.stock_landed_costs.tests.test_stockvaluationlayer import TestStockValuationLCCommon from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data from odoo.tests import tagged, Form @@ -300,3 +301,73 @@ class TestLandedCosts(TestStockLandedCostsCommon): def _error_message(self, actucal_cost, computed_cost): return 'Additional Landed Cost should be %s instead of %s' % (actucal_cost, computed_cost) + + +@tagged('post_install', '-at_install') +class TestLandedCostsWithPurchaseAndInv(TestStockValuationLCCommon): + def test_invoice_after_lc(self): + self.env.company.anglo_saxon_accounting = True + self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' + self.product1.product_tmpl_id.invoice_policy = 'delivery' + self.price_diff_account = self.env['account.account'].create({ + 'name': 'price diff account', + 'code': 'price diff account', + 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, + }) + self.product1.property_account_creditor_price_difference = self.price_diff_account + + # Create PO + po_form = Form(self.env['purchase.order']) + po_form.partner_id = self.env['res.partner'].create({'name': 'vendor'}) + with po_form.order_line.new() as po_line: + po_line.product_id = self.product1 + po_line.product_qty = 1 + po_line.price_unit = 455.0 + order = po_form.save() + order.button_confirm() + + # Receive the goods + receipt = order.picking_ids[0] + receipt.move_lines.quantity_done = 1 + receipt.button_validate() + + # Check SVL and AML + svl = self.env['stock.valuation.layer'].search([('stock_move_id', '=', receipt.move_lines.id)]) + self.assertAlmostEqual(svl.value, 455) + aml = self.env['account.move.line'].search([('account_id', '=', self.stock_valuation_account.id)]) + self.assertAlmostEqual(aml.debit, 455) + + # Create and validate LC + lc = self.env['stock.landed.cost'].create(dict( + picking_ids=[(6, 0, [receipt.id])], + account_journal_id=self.stock_journal.id, + cost_lines=[ + (0, 0, { + 'name': 'equal split', + 'split_method': 'equal', + 'price_unit': 99, + 'product_id': self.productlc1.id, + }), + ], + )) + lc.compute_landed_cost() + lc.button_validate() + + # Check LC, SVL and AML + self.assertAlmostEqual(lc.valuation_adjustment_lines.final_cost, 554) + svl = self.env['stock.valuation.layer'].search([('stock_move_id', '=', receipt.move_lines.id)], order='id desc', limit=1) + self.assertAlmostEqual(svl.value, 99) + aml = self.env['account.move.line'].search([('account_id', '=', self.stock_valuation_account.id)], order='id desc', limit=1) + self.assertAlmostEqual(aml.debit, 99) + + # Create an invoice with the same price + move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form.partner_id = order.partner_id + move_form.purchase_id = order + move = move_form.save() + move.post() + + # Check nothing was posted in the price difference account + price_diff_aml = self.env['account.move.line'].search([('account_id','=', self.price_diff_account.id), ('move_id', '=', move.id)]) + self.assertEqual(len(price_diff_aml), 0, "No line should have been generated in the price difference account.")