From 343f6143d7cadbd170918d5e45c0d5ab2dfbab7d Mon Sep 17 00:00:00 2001 From: "David (dafr)" Date: Fri, 30 Jun 2023 10:48:21 +0000 Subject: [PATCH] [FIX] purchase_stock: get_price_unit with manual valuation layer.account_move_id may not be defined on 'manual' valuation. Use layer.create_date instead which is equal to layer.account_move_id.date. # HOW TO REPRODUCE: - Create a product P, storable in AVCO !! MANUAL !! - Set 'Control Policy' under Purchase to 'Ordered Quantity' - Create a PO for 10 units of P with for $1 each. - Create Vendor Bill -> Confirm - Receive 5 unit of P: Create backorder - Validate backorder ==>> Traceback OPW-3383833 closes odoo/odoo#127218 X-original-commit: b1351ee348207283dcdf7118440b31c03f0d0b4b Signed-off-by: Arnold Moyaux (arm) Signed-off-by: David Fesquet (dafr) --- addons/purchase_stock/models/stock_move.py | 4 +- .../tests/test_stockvaluation.py | 135 ++++++++++++------ 2 files changed, 92 insertions(+), 47 deletions(-) diff --git a/addons/purchase_stock/models/stock_move.py b/addons/purchase_stock/models/stock_move.py index 05636b6d2a5..5c05fdab0af 100644 --- a/addons/purchase_stock/models/stock_move.py +++ b/addons/purchase_stock/models/stock_move.py @@ -50,10 +50,10 @@ class StockMove(models.Model): 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))) + l.value, order.currency_id, order.company_id, l.create_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))) + l.value, order.currency_id, order.company_id, l.create_date, round=False))) invoiced_value = 0 invoiced_qty = 0 for invoice_line in line.invoice_lines: diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py index 966da3be0bb..2c8341e2ac3 100644 --- a/addons/purchase_stock/tests/test_stockvaluation.py +++ b/addons/purchase_stock/tests/test_stockvaluation.py @@ -1942,51 +1942,6 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): 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) - def test_pdiff_and_credit_notes(self): """ Auto FIFO @@ -2484,3 +2439,93 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): svls = self.product1.stock_valuation_layer_ids self.assertEqual(svls.mapped('remaining_value'), [13.0, 12.0, 0.0, 0.0, 0.0, 0.0]) self.assertEqual(svls.mapped('value'), [10.0, 10.0, 1.0, 2.0, -1.0, 3.0]) + + def test_invoice_on_ordered_qty_with_backorder_and_different_currency_automated(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.categ_id.property_valuation = 'real_time' + 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) + + def test_invoice_on_ordered_qty_with_backorder_and_different_currency_manual(self): + """Same test as test_invoice_on_ordered_qty_with_backorder_and_different_currency_automated with manual_periodic valuation + Ensure that the absence of account_move_id on the layers does not generate an Exception + """ + 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.categ_id.property_valuation = 'manual_periodic' + 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)