From 90c055cd35fc0863f16001b5a3eaa8999ac224cb Mon Sep 17 00:00:00 2001 From: Simon Lejeune Date: Fri, 2 Aug 2019 14:02:51 +0000 Subject: [PATCH] [REF] stock_landed_costs: create from vendor bill Add a many2one on the landed cost to the vendor bill. Allow to create a landed cost from a vendor bill if the product is a service. It will use the price_subtotal of the account move line. Add a is_landed_costs_line to separate products of landed costs on the account move line. It's a checkbox. Ticking the checkbox will change the account of the account move if the company is in anglo saxon accounting. Tweak the accounts used by the landed costs so that everything is well balanced (see the added tests). Auto reconcile AML when possible. task-59011 --- .../tests/test_stockvaluation.py | 65 +++-- .../tests/test_stockvaluationlayer.py | 26 +- addons/stock_landed_costs/__manifest__.py | 1 + addons/stock_landed_costs/models/__init__.py | 1 + .../stock_landed_costs/models/account_move.py | 75 ++++++ .../models/stock_landed_cost.py | 17 +- .../tests/test_stockvaluationlayer.py | 235 +++++++++++++++++- .../views/account_move_views.xml | 33 +++ .../views/stock_landed_cost_views.xml | 17 ++ 9 files changed, 435 insertions(+), 35 deletions(-) create mode 100644 addons/stock_landed_costs/models/account_move.py create mode 100644 addons/stock_landed_costs/views/account_move_views.xml 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 + + + + +