From 294a37b0a31ec88165da596c3f3e2dd6f6cb735d Mon Sep 17 00:00:00 2001 From: "Adrien Widart (awt)" Date: Fri, 19 Jan 2024 10:35:06 +0000 Subject: [PATCH] [ADD] stock_landed_costs_company: create LC from branch If the user selects a branch and deactivates the parent company, he will not be able to create any LC. Explanations: Since the company field is a related one that targets the company of the journal, and since the journal belongs to the parent company, the LC created in the branch actually belongs to the parent company, which triggers an access error. Asking users to create branch-specific journals would just cancel all the benefits of the company branch feature. OPW-3651022 closes odoo/odoo#150972 X-original-commit: 915b2e2b8401db937db4162e32e84cf968728072 Signed-off-by: Arnold Moyaux (arm) Signed-off-by: Adrien Widart (awt) --- .tx/config | 9 ++ addons/stock_landed_costs_company/__init__.py | 12 ++ .../__manifest__.py | 18 +++ .../i18n/stock_landed_costs_company.pot | 26 +++++ .../models/__init__.py | 4 + .../models/stock_landed_cost.py | 10 ++ .../tests/__init__.py | 3 + .../tests/test_stock_landed_costs_branches.py | 103 ++++++++++++++++++ 8 files changed, 185 insertions(+) create mode 100644 addons/stock_landed_costs_company/__init__.py create mode 100644 addons/stock_landed_costs_company/__manifest__.py create mode 100644 addons/stock_landed_costs_company/i18n/stock_landed_costs_company.pot create mode 100644 addons/stock_landed_costs_company/models/__init__.py create mode 100644 addons/stock_landed_costs_company/models/stock_landed_cost.py create mode 100644 addons/stock_landed_costs_company/tests/__init__.py create mode 100644 addons/stock_landed_costs_company/tests/test_stock_landed_costs_branches.py diff --git a/.tx/config b/.tx/config index ea2491f247e..c8d50c1b6e3 100644 --- a/.tx/config +++ b/.tx/config @@ -2098,6 +2098,15 @@ resource_name = stock_landed_costs replace_edited_strings = false keep_translations = false +[o:odoo:p:odoo-17:r:stock_landed_costs_company] +file_filter = addons/stock_landed_costs_company/i18n/.po +source_file = addons/stock_landed_costs_company/i18n/stock_landed_costs_company.pot +type = PO +minimum_perc = 0 +resource_name = stock_landed_costs_company +replace_edited_strings = false +keep_translations = false + [o:odoo:p:odoo-17:r:stock_picking_batch] file_filter = addons/stock_picking_batch/i18n/.po source_file = addons/stock_picking_batch/i18n/stock_picking_batch.pot diff --git a/addons/stock_landed_costs_company/__init__.py b/addons/stock_landed_costs_company/__init__.py new file mode 100644 index 00000000000..ef61079ec47 --- /dev/null +++ b/addons/stock_landed_costs_company/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models + +def _stock_landed_costs_company_post_init(env): + env.cr.execute(""" + UPDATE stock_landed_cost cost + SET company_id = journal.company_id + FROM account_journal journal + WHERE cost.account_journal_id = journal.id + """) diff --git a/addons/stock_landed_costs_company/__manifest__.py b/addons/stock_landed_costs_company/__manifest__.py new file mode 100644 index 00000000000..1adf7ead9ae --- /dev/null +++ b/addons/stock_landed_costs_company/__manifest__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Landed Costs for company\'s branches', + 'version': '1.0', + 'description': """ + This module is a patch that stores the company_id field on the landed cost model. + That way, it is possible to create/use landed costs from a branch. + """, + 'depends': ['stock_landed_costs'], + 'category': 'Inventory/Inventory', + 'sequence': 16, + 'installable': True, + 'auto_install': True, + 'post_init_hook': '_stock_landed_costs_company_post_init', + 'license': 'LGPL-3', +} diff --git a/addons/stock_landed_costs_company/i18n/stock_landed_costs_company.pot b/addons/stock_landed_costs_company/i18n/stock_landed_costs_company.pot new file mode 100644 index 00000000000..6efa3b1c8cb --- /dev/null +++ b/addons/stock_landed_costs_company/i18n/stock_landed_costs_company.pot @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_landed_costs_company +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-01-25 07:53+0000\n" +"PO-Revision-Date: 2024-01-25 07:53+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_landed_costs_company +#: model:ir.model.fields,field_description:stock_landed_costs_company.field_stock_landed_cost__company_id +msgid "Company" +msgstr "" + +#. module: stock_landed_costs_company +#: model:ir.model,name:stock_landed_costs_company.model_stock_landed_cost +msgid "Stock Landed Cost" +msgstr "" diff --git a/addons/stock_landed_costs_company/models/__init__.py b/addons/stock_landed_costs_company/models/__init__.py new file mode 100644 index 00000000000..cc408347617 --- /dev/null +++ b/addons/stock_landed_costs_company/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import stock_landed_cost diff --git a/addons/stock_landed_costs_company/models/stock_landed_cost.py b/addons/stock_landed_costs_company/models/stock_landed_cost.py new file mode 100644 index 00000000000..bf438a8c148 --- /dev/null +++ b/addons/stock_landed_costs_company/models/stock_landed_cost.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class StockLandedCost(models.Model): + _inherit = 'stock.landed.cost' + + company_id = fields.Many2one('res.company', 'Company', required=True, related=False, default=lambda self: self.env.company) diff --git a/addons/stock_landed_costs_company/tests/__init__.py b/addons/stock_landed_costs_company/tests/__init__.py new file mode 100644 index 00000000000..a7377466cf9 --- /dev/null +++ b/addons/stock_landed_costs_company/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import test_stock_landed_costs_branches diff --git a/addons/stock_landed_costs_company/tests/test_stock_landed_costs_branches.py b/addons/stock_landed_costs_company/tests/test_stock_landed_costs_branches.py new file mode 100644 index 00000000000..42b07e0cfc4 --- /dev/null +++ b/addons/stock_landed_costs_company/tests/test_stock_landed_costs_branches.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.stock_landed_costs.tests.test_stockvaluationlayer import TestStockValuationLCCommon +from odoo.tests import tagged, Form + + +@tagged('post_install', '-at_install') +class TestStockLandedCostsBranches(TestStockValuationLCCommon): + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + cls.company = cls.env.company + cls.branch = cls.env['res.company'].create({ + 'name': 'Branch', + 'parent_id': cls.company.id, + }) + cls.env['account.chart.template'].try_loading(cls.company.chart_template, company=cls.branch, install_demo=False) + cls.env.user.company_id = cls.branch + + cls.vendor1 = cls.env['res.partner'].create({'name': 'vendor1'}) + + cls.product1.categ_id.property_cost_method = 'fifo' + + def test_create_lc_from_branch(self): + """ + From a company's branch, create a LC and ensure it impacts the SVL + """ + warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.branch.id)], limit=1) + supplier_location = self.env.ref('stock.stock_location_suppliers') + + receipt = self.env['stock.picking'].create({ + 'location_id': supplier_location.id, + 'location_dest_id': warehouse.lot_stock_id.id, + 'picking_type_id': warehouse.in_type_id.id, + 'move_ids': [(0, 0, { + 'name': self.product1.name, + 'location_id': supplier_location.id, + 'location_dest_id': warehouse.lot_stock_id.id, + 'picking_type_id': warehouse.in_type_id.id, + 'product_id': self.product1.id, + 'product_uom_qty': 1, + 'product_uom': self.product1.uom_id.id, + 'price_unit': 10, + })], + }) + receipt.action_confirm() + receipt.action_assign() + receipt.move_line_ids.quantity = 1 + receipt.button_validate() + + lc_form = Form(self.env['stock.landed.cost']) + lc_form.picking_ids.add(receipt) + with lc_form.cost_lines.new() as cost_line: + cost_line.product_id = self.productlc1 + cost_line.price_unit = 5 + lc = lc_form.save() + lc.compute_landed_cost() + lc.button_validate() + + self.assertEqual(self.product1.value_svl, 15) + self.assertEqual(self.product1.quantity_svl, 1) + self.assertEqual(self.product1.standard_price, 15) + + def test_lc_generated_from_bill(self): + """ + Confirm PO, receive products, post bill and generate LC + """ + po_form = Form(self.env['purchase.order']) + po_form.partner_id = self.vendor1 + with po_form.order_line.new() as po_line: + po_line.product_id = self.product1 + po_line.product_qty = 1 + po_line.price_unit = 10 + po_line.taxes_id.clear() + po = po_form.save() + po.button_confirm() + + receipt = po.picking_ids + receipt.move_line_ids.quantity = 1 + receipt.button_validate() + + action = po.action_create_invoice() + bill = self.env['account.move'].browse(action['res_id']) + bill_form = Form(bill) + bill_form.invoice_date = bill_form.date + with bill_form.invoice_line_ids.new() as inv_line: + inv_line.product_id = self.productlc1 + inv_line.price_unit = 5 + bill = bill_form.save() + bill.action_post() + + action = bill.button_create_landed_costs() + lc_form = Form(self.env[action['res_model']].browse(action['res_id'])) + lc_form.picking_ids.add(receipt) + lc = lc_form.save() + lc.button_validate() + + self.assertEqual(self.product1.value_svl, 15) + self.assertEqual(self.product1.quantity_svl, 1) + self.assertEqual(self.product1.standard_price, 15)