diff --git a/addons/stock_account/tests/test_stockvaluation.py b/addons/stock_account/tests/test_stockvaluation.py
index e12b8fa29f9..6cfac5552b8 100644
--- a/addons/stock_account/tests/test_stockvaluation.py
+++ b/addons/stock_account/tests/test_stockvaluation.py
@@ -8,6 +8,44 @@ from odoo.fields import Datetime
from odoo.tests.common import Form, SavepointCase
+def _create_accounting_data(env):
+ """Create the accounts and journals used in stock valuation.
+
+ :param env: environment used to create the records
+ :return: an input account, an output account, a valuation account, an expense account, a stock journal
+ """
+ stock_input_account = env['account.account'].create({
+ 'name': 'Stock Input',
+ 'code': 'StockIn',
+ 'user_type_id': env.ref('account.data_account_type_current_assets').id,
+ 'reconcile': True,
+ })
+ stock_output_account = env['account.account'].create({
+ 'name': 'Stock Output',
+ 'code': 'StockOut',
+ 'user_type_id': env.ref('account.data_account_type_current_assets').id,
+ 'reconcile': True,
+ })
+ stock_valuation_account = env['account.account'].create({
+ 'name': 'Stock Valuation',
+ 'code': 'Stock Valuation',
+ 'user_type_id': env.ref('account.data_account_type_current_assets').id,
+ 'reconcile': True,
+ })
+ expense_account = env['account.account'].create({
+ 'name': 'Expense Account',
+ 'code': 'Expense Account',
+ 'user_type_id': env.ref('account.data_account_type_expenses').id,
+ 'reconcile': True,
+ })
+ stock_journal = env['account.journal'].create({
+ 'name': 'Stock Journal',
+ 'code': 'STJTEST',
+ 'type': 'general',
+ })
+ return stock_input_account, stock_output_account, stock_valuation_account, expense_account, stock_journal
+
+
class TestStockValuation(SavepointCase):
@classmethod
def setUpClass(cls):
@@ -37,34 +75,9 @@ class TestStockValuation(SavepointCase):
'groups_id': [(6, 0, [cls.env.ref('stock.group_stock_user').id])]
})
+ cls.stock_input_account, cls.stock_output_account, cls.stock_valuation_account, cls.expense_account, cls.stock_journal = _create_accounting_data(cls.env)
cls.product1.categ_id.property_valuation = 'real_time'
cls.product2.categ_id.property_valuation = 'real_time'
- Account = cls.env['account.account']
- cls.stock_input_account = Account.create({
- 'name': 'Stock Input',
- 'code': 'StockIn',
- 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id,
- })
- cls.stock_output_account = Account.create({
- 'name': 'Stock Output',
- 'code': 'StockOut',
- 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id,
- })
- cls.stock_valuation_account = Account.create({
- 'name': 'Stock Valuation',
- 'code': 'Stock Valuation',
- 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id,
- })
- cls.expense_account = Account.create({
- 'name': 'Expense Account',
- 'code': 'Expense Account',
- 'user_type_id': cls.env.ref('account.data_account_type_expenses').id,
- })
- cls.stock_journal = cls.env['account.journal'].create({
- 'name': 'Stock Journal',
- 'code': 'STJTEST',
- 'type': 'general',
- })
cls.product1.write({
'property_account_expense_id': cls.expense_account.id,
})
diff --git a/addons/stock_account/tests/test_stockvaluationlayer.py b/addons/stock_account/tests/test_stockvaluationlayer.py
index dd2d65dd75e..1cc6df146b6 100644
--- a/addons/stock_account/tests/test_stockvaluationlayer.py
+++ b/addons/stock_account/tests/test_stockvaluationlayer.py
@@ -3,6 +3,7 @@
""" Implementation of "INVENTORY VALUATION TESTS (With valuation layers)" spreadsheet. """
+from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data
from odoo.tests import Form, tagged
from odoo.tests.common import SavepointCase, TransactionCase
@@ -709,8 +710,22 @@ class TestStockValuationChangeCostMethod(TestStockValuationCommon):
self.assertEqual(self.product1.quantity_svl, 19)
-@tagged('post_install', '-at_install')
class TestStockValuationChangeValuation(TestStockValuationCommon):
+ @classmethod
+ def setUpClass(cls):
+ super(TestStockValuationChangeValuation, cls).setUpClass()
+ cls.stock_input_account, cls.stock_output_account, cls.stock_valuation_account, cls.expense_account, cls.stock_journal = _create_accounting_data(cls.env)
+ cls.product1.categ_id.property_valuation = 'real_time'
+ cls.product1.write({
+ 'property_account_expense_id': cls.expense_account.id,
+ })
+ cls.product1.categ_id.write({
+ 'property_stock_account_input_categ_id': cls.stock_input_account.id,
+ 'property_stock_account_output_categ_id': cls.stock_output_account.id,
+ 'property_stock_valuation_account_id': cls.stock_valuation_account.id,
+ 'property_stock_journal': cls.stock_journal.id,
+ })
+
def test_standard_manual_to_auto_1(self):
self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
self.product1.product_tmpl_id.categ_id.property_valuation = 'manual_periodic'
@@ -743,9 +758,16 @@ class TestStockValuationChangeValuation(TestStockValuationCommon):
self.assertEqual(len(self.product1.stock_valuation_layer_ids.mapped('account_move_id')), 0)
self.assertEqual(len(self.product1.stock_valuation_layer_ids), 1)
- cat2 = self.env['product.category'].create({'name': 'fifo'})
+ cat2 = self.env['product.category'].create({'name': 'standard auto'})
cat2.property_cost_method = 'standard'
cat2.property_valuation = 'real_time'
+ cat2.write({
+ 'property_stock_account_input_categ_id': self.stock_input_account.id,
+ 'property_stock_account_output_categ_id': self.stock_output_account.id,
+ 'property_stock_valuation_account_id': self.stock_valuation_account.id,
+ 'property_stock_journal': self.stock_journal.id,
+ })
+
self.product1.categ_id = cat2
self.assertEqual(self.product1.value_svl, 100)
diff --git a/addons/stock_landed_costs/__manifest__.py b/addons/stock_landed_costs/__manifest__.py
index 88e4de8dbd9..d11472b8e0b 100644
--- a/addons/stock_landed_costs/__manifest__.py
+++ b/addons/stock_landed_costs/__manifest__.py
@@ -19,6 +19,7 @@ This module allows you to easily add extra costs on pickings and decide the spli
'security/ir.model.access.csv',
'security/stock_landed_cost_security.xml',
'data/stock_landed_cost_data.xml',
+ 'views/account_move_views.xml',
'views/product_views.xml',
'views/stock_landed_cost_views.xml',
'views/stock_valuation_layer_views.xml',
diff --git a/addons/stock_landed_costs/models/__init__.py b/addons/stock_landed_costs/models/__init__.py
index a3a586e5c1f..43a7e03eabd 100644
--- a/addons/stock_landed_costs/models/__init__.py
+++ b/addons/stock_landed_costs/models/__init__.py
@@ -5,5 +5,6 @@ from . import product
from . import res_company
from . import res_config_settings
from . import stock_landed_cost
+from . import account_move
from . import stock_valuation_layer
diff --git a/addons/stock_landed_costs/models/account_move.py b/addons/stock_landed_costs/models/account_move.py
new file mode 100644
index 00000000000..ae50e6d5ec5
--- /dev/null
+++ b/addons/stock_landed_costs/models/account_move.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class AccountMove(models.Model):
+ _inherit = 'account.move'
+
+ landed_costs_ids = fields.One2many('stock.landed.cost', 'vendor_bill_id', string='Landed Costs')
+ landed_costs_visible = fields.Boolean(compute='_compute_landed_costs_visible')
+
+ @api.depends('line_ids', 'line_ids.is_landed_costs_line')
+ def _compute_landed_costs_visible(self):
+ for account_move in self:
+ if account_move.landed_costs_ids:
+ account_move.landed_costs_visible = False
+ else:
+ account_move.landed_costs_visible = any(line.is_landed_costs_line for line in account_move.line_ids)
+
+ def button_create_landed_costs(self):
+ """Create a `stock.landed.cost` record associated to the account move of `self`, each
+ `stock.landed.costs` lines mirroring the current `account.move.line` of self.
+ """
+ self.ensure_one()
+ landed_costs_lines = self.line_ids.filtered(lambda line: line.is_landed_costs_line)
+
+ landed_costs = self.env['stock.landed.cost'].create({
+ 'vendor_bill_id': self.id,
+ 'cost_lines': [(0, 0, {
+ 'product_id': l.product_id.id,
+ 'name': l.product_id.name,
+ 'account_id': l.product_id.product_tmpl_id.get_product_accounts()['stock_input'].id,
+ 'price_unit': l.price_subtotal,
+ 'split_method': 'equal',
+ }) for l in landed_costs_lines],
+ })
+ action = self.env.ref('stock_landed_costs.action_stock_landed_cost').read()[0]
+ return dict(action, view_mode='form', res_id=landed_costs.id, views=[(False, 'form')])
+
+ def action_view_landed_costs(self):
+ self.ensure_one()
+ action = self.env.ref('stock_landed_costs.action_stock_landed_cost').read()[0]
+ domain = [('id', 'in', self.landed_costs_ids.ids)]
+ context = dict(self.env.context, default_vendor_bill_id=self.id)
+ views = [(self.env.ref('stock_landed_costs.view_stock_landed_cost_tree2').id, 'tree'), (False, 'form'), (False, 'kanban')]
+ return dict(action, domain=domain, context=context, views=views)
+
+
+class AccountMoveLine(models.Model):
+ _inherit = 'account.move.line'
+
+ product_type = fields.Selection(related='product_id.type', readonly=True)
+ is_landed_costs_line = fields.Boolean()
+
+ @api.onchange('is_landed_costs_line')
+ def _onchange_is_landed_costs_line(self):
+ """Mark an invoice line as a landed cost line and adapt `self.account_id`. The default
+ value can be set according to `self.product_id.landed_cost_ok`."""
+ if self.product_id:
+ accounts = self.product_id.product_tmpl_id._get_product_accounts()
+ if self.product_type != 'service':
+ self.account_id = accounts['expense']
+ self.is_landed_costs_line = False
+ elif self.is_landed_costs_line and self.move_id.company_id.anglo_saxon_accounting:
+ self.account_id = accounts['stock_input']
+ else:
+ self.account_id = accounts['expense']
+
+ @api.onchange('product_id')
+ def _onchange_is_landed_costs_line_product(self):
+ if self.product_id.landed_cost_ok:
+ self.is_landed_costs_line = True
+ else:
+ self.is_landed_costs_line = False
diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py
index a516da51338..2e8b27357ce 100644
--- a/addons/stock_landed_costs/models/stock_landed_cost.py
+++ b/addons/stock_landed_costs/models/stock_landed_cost.py
@@ -118,6 +118,7 @@ class LandedCost(models.Model):
'date': cost.date,
'ref': cost.name,
'line_ids': [],
+ 'type': 'entry',
}
for line in cost.valuation_adjustment_lines.filtered(lambda line: line.move_id):
remaining_qty = sum(line.move_id.stock_valuation_layer_ids.mapped('remaining_qty'))
@@ -155,6 +156,13 @@ class LandedCost(models.Model):
move = move.create(move_vals)
cost.write({'state': 'done', 'account_move_id': move.id})
move.post()
+
+ if cost.vendor_bill_id and cost.vendor_bill_id.state == 'posted' and cost.company_id.anglo_saxon_accounting:
+ all_amls = cost.vendor_bill_id.line_ids | cost.account_move_id.line_ids
+ for product in cost.cost_lines.product_id:
+ accounts = product.product_tmpl_id.get_product_accounts()
+ input_account = accounts['stock_input']
+ all_amls.filtered(lambda aml: aml.account_id == input_account).reconcile()
return True
def _check_sum(self):
@@ -285,7 +293,8 @@ class LandedCostLine(models.Model):
self.name = self.product_id.name or ''
self.split_method = 'equal'
self.price_unit = self.product_id.standard_price or 0.0
- self.account_id = self.product_id.property_account_expense_id.id or self.product_id.categ_id.property_account_expense_categ_id.id
+ accounts_data = self.product_id.product_tmpl_id.get_product_accounts()
+ self.account_id = accounts_data['stock_input']
class AdjustmentLines(models.Model):
@@ -341,7 +350,7 @@ class AdjustmentLines(models.Model):
if self.move_id._is_dropshipped():
debit_account_id = accounts.get('expense') and accounts['expense'].id or False
already_out_account_id = accounts['stock_output'].id
- credit_account_id = self.cost_line_id.account_id.id or cost_product.property_account_expense_id.id or cost_product.categ_id.property_account_expense_categ_id.id
+ credit_account_id = self.cost_line_id.account_id.id or cost_product.categ_id.property_stock_account_input_categ_id.id
if not credit_account_id:
raise UserError(_('Please configure Stock Expense Account for product: %s.') % (cost_product.name))
@@ -394,12 +403,12 @@ class AdjustmentLines(models.Model):
AccountMoveLine.append([0, 0, debit_line])
AccountMoveLine.append([0, 0, credit_line])
- # TDE FIXME: oh dear
if self.env.company.anglo_saxon_accounting:
+ expense_account_id = self.product_id.product_tmpl_id.get_product_accounts()['expense'].id
debit_line = dict(base_line,
name=(self.name + ": " + str(qty_out) + _(' already out')),
quantity=0,
- account_id=credit_account_id)
+ account_id=expense_account_id)
credit_line = dict(base_line,
name=(self.name + ": " + str(qty_out) + _(' already out')),
quantity=0,
diff --git a/addons/stock_landed_costs/tests/test_stockvaluationlayer.py b/addons/stock_landed_costs/tests/test_stockvaluationlayer.py
index db4525b8af8..b54273790f9 100644
--- a/addons/stock_landed_costs/tests/test_stockvaluationlayer.py
+++ b/addons/stock_landed_costs/tests/test_stockvaluationlayer.py
@@ -5,6 +5,7 @@
from odoo.tests import Form, tagged
from odoo.addons.stock_account.tests.test_stockvaluationlayer import TestStockValuationCommon
+from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data
class TestStockValuationLC(TestStockValuationCommon):
@@ -16,11 +17,55 @@ class TestStockValuationLC(TestStockValuationCommon):
'type': 'service',
'categ_id': cls.env.ref('product.product_category_all').id,
})
+ cls.stock_input_account, cls.stock_output_account, cls.stock_valuation_account, cls.expense_account, cls.stock_journal = _create_accounting_data(cls.env)
+ cls.product1.write({
+ 'property_account_expense_id': cls.expense_account.id,
+ })
+ cls.productlc1.write({
+ 'property_account_expense_id': cls.expense_account.id,
+ })
+ cls.product1.categ_id.write({
+ 'property_stock_account_input_categ_id': cls.stock_input_account.id,
+ 'property_stock_account_output_categ_id': cls.stock_output_account.id,
+ 'property_stock_valuation_account_id': cls.stock_valuation_account.id,
+ 'property_stock_journal': cls.stock_journal.id,
+ })
+ cls.payable_account = cls.env['account.account'].create({
+ 'name': 'payable',
+ 'code': 'payable',
+ 'user_type_id': cls.env.ref('account.data_account_type_payable').id,
+ 'reconcile': True,
+ })
+
+ def _get_stock_input_move_lines(self):
+ return self.env['account.move.line'].search([
+ ('account_id', '=', self.stock_input_account.id),
+ ], order='date, id')
+
+ def _get_stock_output_move_lines(self):
+ return self.env['account.move.line'].search([
+ ('account_id', '=', self.stock_output_account.id),
+ ], order='date, id')
+
+ def _get_stock_valuation_move_lines(self):
+ return self.env['account.move.line'].search([
+ ('account_id', '=', self.stock_valuation_account.id),
+ ], order='date, id')
+
+ def _get_payable_move_lines(self):
+ return self.env['account.move.line'].search([
+ ('account_id', '=', self.payable_account.id),
+ ], order='id')
+
+ def _get_expense_move_lines(self):
+ return self.env['account.move.line'].search([
+ ('account_id', '=', self.expense_account.id),
+ ], order='id')
def _make_lc(self, move, amount):
picking = move.picking_id
lc = Form(self.env['stock.landed.cost'])
- lc.account_journal_id = self.env['account.journal'].search([('name', 'ilike', '%misc%')], limit=1)
+ lc.account_journal_id = self.stock_journal
lc.picking_ids.add(move.picking_id)
with lc.cost_lines.new() as cost_line:
cost_line.product_id = self.productlc1
@@ -31,7 +76,6 @@ class TestStockValuationLC(TestStockValuationCommon):
return lc
-@tagged('post_install', '-at_install')
class TestStockValuationLCFIFO(TestStockValuationLC):
def setUp(self):
super(TestStockValuationLCFIFO, self).setUp()
@@ -96,7 +140,6 @@ class TestStockValuationLCFIFO(TestStockValuationLC):
self.assertEqual(in_svl.value, 225)
-@tagged('post_install', '-at_install')
class TestStockValuationLCAVCO(TestStockValuationLC):
def setUp(self):
super(TestStockValuationLCAVCO, self).setUp()
@@ -137,3 +180,189 @@ class TestStockValuationLCAVCO(TestStockValuationLC):
self.assertEqual(self.product1.value_svl, 375)
self.assertEqual(self.product1.quantity_svl, 19)
+
+
+class TestStockValuationLCFIFOVB(TestStockValuationLC):
+ @classmethod
+ def setUpClass(cls):
+ super(TestStockValuationLCFIFOVB, cls).setUpClass()
+ cls.vendor1 = cls.env['res.partner'].search([], limit=1)
+ cls.vendor1.property_account_payable_id = cls.payable_account
+ cls.vendor2 = cls.env['res.partner'].search([], limit=2)[-1]
+ cls.vendor2.property_account_payable_id = cls.payable_account
+ cls.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
+ cls.product1.product_tmpl_id.categ_id.property_valuation = 'real_time'
+
+ def test_vendor_bill_flow_anglo_saxon_1(self):
+ """In anglo saxon accounting, receive 10@10 and invoice. Then invoice 1@50 as a landed costs
+ and create a linked landed costs record.
+ """
+ self.env.company.anglo_saxon_accounting = True
+
+ # Create an RFQ for self.product1, 10@10
+ rfq = Form(self.env['purchase.order'])
+ rfq.partner_id = self.vendor1
+
+ with rfq.order_line.new() as po_line:
+ po_line.product_id = self.product1
+ po_line.price_unit = 10
+ po_line.product_qty = 10
+ po_line.taxes_id.clear()
+
+ rfq = rfq.save()
+ rfq.button_confirm()
+
+ # Process the receipt
+ receipt = rfq.picking_ids
+ wiz = receipt.button_validate()
+ wiz = self.env['stock.immediate.transfer'].browse(wiz['res_id']).process()
+ self.assertEqual(rfq.order_line.qty_received, 10)
+
+ input_aml = self._get_stock_input_move_lines()[-1]
+ self.assertEqual(input_aml.debit, 0)
+ self.assertEqual(input_aml.credit, 100)
+ valuation_aml = self._get_stock_valuation_move_lines()[-1]
+ self.assertEqual(valuation_aml.debit, 100)
+ self.assertEqual(valuation_aml.credit, 0)
+
+ # Create a vebdor bill for the RFQ
+ action = rfq.action_view_invoice()
+ vb = Form(self.env['account.move'].with_context(action['context']))
+ vb = vb.save()
+ vb.post()
+
+ input_aml = self._get_stock_input_move_lines()[-1]
+ self.assertEqual(input_aml.debit, 100)
+ self.assertEqual(input_aml.credit, 0)
+ payable_aml = self._get_payable_move_lines()[-1]
+ self.assertEqual(payable_aml.debit, 0)
+ self.assertEqual(payable_aml.credit, 100)
+
+ # Create a vendor bill for a landed cost product, post it and validate a landed cost
+ # linked to this vendor bill. LC; 1@50
+ lcvb = Form(self.env['account.move'].with_context(default_type='in_invoice'))
+ lcvb.partner_id = self.vendor2
+ with lcvb.invoice_line_ids.new() as inv_line:
+ inv_line.product_id = self.productlc1
+ inv_line.price_unit = 50
+ inv_line.is_landed_costs_line = True
+ with lcvb.invoice_line_ids.edit(0) as inv_line:
+ inv_line.tax_ids.clear()
+ lcvb = lcvb.save()
+ lcvb.post()
+
+ input_aml = self._get_stock_input_move_lines()[-1]
+ self.assertEqual(input_aml.debit, 50)
+ self.assertEqual(input_aml.credit, 0)
+ payable_aml = self._get_payable_move_lines()[-1]
+ self.assertEqual(payable_aml.debit, 0)
+ self.assertEqual(payable_aml.credit, 50)
+
+ action = lcvb.button_create_landed_costs()
+ lc = Form(self.env[action['res_model']].browse(action['res_id']))
+ lc.picking_ids.add(receipt)
+ lc = lc.save()
+ lc.button_validate()
+
+ self.assertEqual(lc.cost_lines.price_unit, 50)
+ self.assertEqual(lc.cost_lines.product_id, self.productlc1)
+
+ input_aml = self._get_stock_input_move_lines()[-1]
+ self.assertEqual(input_aml.debit, 0)
+ self.assertEqual(input_aml.credit, 50)
+ valuation_aml = self._get_stock_valuation_move_lines()[-1]
+ self.assertEqual(valuation_aml.debit, 50)
+ self.assertEqual(valuation_aml.credit, 0)
+
+ # Check reconciliation of input aml of lc
+ lc_input_aml = lc.account_move_id.line_ids.filtered(lambda aml: aml.account_id == self.stock_input_account)
+ self.assertTrue(len(lc_input_aml.full_reconcile_id), 1)
+
+ self.assertEqual(self.product1.quantity_svl, 10)
+ self.assertEqual(self.product1.value_svl, 150)
+
+ def test_vendor_bill_flow_continental_1(self):
+ """In continental accounting, receive 10@10 and invoice. Then invoice 1@50 as a landed costs
+ and create a linked landed costs record.
+ """
+ self.env.company.anglo_saxon_accounting = False
+
+ # Create an RFQ for self.product1, 10@10
+ rfq = Form(self.env['purchase.order'])
+ rfq.partner_id = self.vendor1
+
+ with rfq.order_line.new() as po_line:
+ po_line.product_id = self.product1
+ po_line.price_unit = 10
+ po_line.product_qty = 10
+ po_line.taxes_id.clear()
+
+ rfq = rfq.save()
+ rfq.button_confirm()
+
+ # Process the receipt
+ receipt = rfq.picking_ids
+ wiz = receipt.button_validate()
+ wiz = self.env['stock.immediate.transfer'].browse(wiz['res_id']).process()
+ self.assertEqual(rfq.order_line.qty_received, 10)
+
+ input_aml = self._get_stock_input_move_lines()[-1]
+ self.assertEqual(input_aml.debit, 0)
+ self.assertEqual(input_aml.credit, 100)
+ valuation_aml = self._get_stock_valuation_move_lines()[-1]
+ self.assertEqual(valuation_aml.debit, 100)
+ self.assertEqual(valuation_aml.credit, 0)
+
+ # Create a vebdor bill for the RFQ
+ action = rfq.action_view_invoice()
+ vb = Form(self.env['account.move'].with_context(action['context']))
+ vb = vb.save()
+ vb.post()
+
+ expense_aml = self._get_expense_move_lines()[-1]
+ self.assertEqual(expense_aml.debit, 100)
+ self.assertEqual(expense_aml.credit, 0)
+
+ payable_aml = self._get_payable_move_lines()[-1]
+ self.assertEqual(payable_aml.debit, 0)
+ self.assertEqual(payable_aml.credit, 100)
+
+ # Create a vendor bill for a landed cost product, post it and validate a landed cost
+ # linked to this vendor bill. LC; 1@50
+ lcvb = Form(self.env['account.move'].with_context(default_type='in_invoice'))
+ lcvb.partner_id = self.vendor2
+ with lcvb.invoice_line_ids.new() as inv_line:
+ inv_line.product_id = self.productlc1
+ inv_line.price_unit = 50
+ inv_line.is_landed_costs_line = True
+ with lcvb.invoice_line_ids.edit(0) as inv_line:
+ inv_line.tax_ids.clear()
+ lcvb = lcvb.save()
+ lcvb.post()
+
+ expense_aml = self._get_expense_move_lines()[-1]
+ self.assertEqual(expense_aml.debit, 50)
+ self.assertEqual(expense_aml.credit, 0)
+ payable_aml = self._get_payable_move_lines()[-1]
+ self.assertEqual(payable_aml.debit, 0)
+ self.assertEqual(payable_aml.credit, 50)
+
+ action = lcvb.button_create_landed_costs()
+ lc = Form(self.env[action['res_model']].browse(action['res_id']))
+ lc.picking_ids.add(receipt)
+ lc = lc.save()
+ lc.button_validate()
+
+ self.assertEqual(lc.cost_lines.price_unit, 50)
+ self.assertEqual(lc.cost_lines.product_id, self.productlc1)
+
+ input_aml = self._get_stock_input_move_lines()[-1]
+ self.assertEqual(input_aml.debit, 0)
+ self.assertEqual(input_aml.credit, 50)
+ valuation_aml = self._get_stock_valuation_move_lines()[-1]
+ self.assertEqual(valuation_aml.debit, 50)
+ self.assertEqual(valuation_aml.credit, 0)
+
+ self.assertEqual(self.product1.quantity_svl, 10)
+ self.assertEqual(self.product1.value_svl, 150)
+
diff --git a/addons/stock_landed_costs/views/account_move_views.xml b/addons/stock_landed_costs/views/account_move_views.xml
new file mode 100644
index 00000000000..97ffde5283d
--- /dev/null
+++ b/addons/stock_landed_costs/views/account_move_views.xml
@@ -0,0 +1,33 @@
+
+
+
+ account.view.move.form.inherited
+ account.move
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/stock_landed_costs/views/stock_landed_cost_views.xml b/addons/stock_landed_costs/views/stock_landed_cost_views.xml
index 562dce04989..6d10961dc72 100644
--- a/addons/stock_landed_costs/views/stock_landed_cost_views.xml
+++ b/addons/stock_landed_costs/views/stock_landed_cost_views.xml
@@ -34,6 +34,7 @@
+
@@ -119,6 +120,22 @@
+
+ stock.landed.cost.tree
+ stock.landed.cost
+ 1000
+
+
+
+
+
+
+
+
+
+
+
+
stock.landed.cost.kanban
stock.landed.cost