diff --git a/account_invoice_inter_company/tests/test_inter_company_invoice.py b/account_invoice_inter_company/tests/test_inter_company_invoice.py index 0fbc954fabe..6a1457c1f94 100644 --- a/account_invoice_inter_company/tests/test_inter_company_invoice.py +++ b/account_invoice_inter_company/tests/test_inter_company_invoice.py @@ -22,19 +22,14 @@ def setUpClass(cls): "invoice_auto_validation": True, } ) - cls.partner_company_a = cls.env["res.partner"].create( - {"name": cls.company_a.name, "is_company": True} - ) - cls.company_a.partner_id = cls.partner_company_a + cls.partner_company_a = cls.company_a.partner_id cls.company_b = cls.env["res.company"].create( { "name": "Company B", "invoice_auto_validation": True, } ) - cls.partner_company_b = cls.env["res.partner"].create( - {"name": cls.company_b.name, "is_company": True} - ) + cls.partner_company_b = cls.company_b.partner_id cls.child_partner_company_b = cls.env["res.partner"].create( { "name": "Child, Company B", diff --git a/purchase_sale_inter_company/README.rst b/purchase_sale_inter_company/README.rst index 7a92739e0b5..ab131563d06 100644 --- a/purchase_sale_inter_company/README.rst +++ b/purchase_sale_inter_company/README.rst @@ -116,6 +116,10 @@ Contributors - Maksym Yankin +- \`Komit \`: + + - Cuong Nguyen Mtm + Maintainers ----------- diff --git a/purchase_sale_inter_company/__manifest__.py b/purchase_sale_inter_company/__manifest__.py index 47e9106da3c..7748a37db3a 100644 --- a/purchase_sale_inter_company/__manifest__.py +++ b/purchase_sale_inter_company/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Inter Company Module for Purchase to Sale Order", "summary": "Intercompany PO/SO rules", - "version": "16.0.1.1.1", + "version": "17.0.1.0.0", "category": "Purchase Management", "website": "https://github.com/OCA/multi-company", "author": "Odoo SA, Akretion, Tecnativa, Odoo Community Association (OCA)", diff --git a/purchase_sale_inter_company/models/account_move.py b/purchase_sale_inter_company/models/account_move.py index e7f83d6ad41..da9ffb7ac02 100644 --- a/purchase_sale_inter_company/models/account_move.py +++ b/purchase_sale_inter_company/models/account_move.py @@ -3,6 +3,8 @@ # Copyright 2018-2019 Tecnativa - Carlos Dauden # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from markupsafe import Markup + from odoo import _, models @@ -28,4 +30,4 @@ def _link_invoice_purchase(self, dest_invoice): message = _("This vendor bill is related with: {}").format( ",".join([ref.format(o.id, o.name) for o in orders]) ) - dest_invoice.message_post(body=message) + dest_invoice.message_post(body=Markup(message)) diff --git a/purchase_sale_inter_company/models/purchase_order.py b/purchase_sale_inter_company/models/purchase_order.py index 9422a455107..0b3f2bec331 100644 --- a/purchase_sale_inter_company/models/purchase_order.py +++ b/purchase_sale_inter_company/models/purchase_order.py @@ -80,6 +80,7 @@ def _inter_company_create_sale_order(self, dest_company): # check pricelist currency should be same with PO/SO document if self.currency_id.id != ( company_partner.property_product_pricelist.currency_id.id + or dest_company.currency_id.id ): raise UserError( _( @@ -181,6 +182,7 @@ def button_cancel(self): for so in sale_orders: if so.state not in ["draft", "sent", "cancel"]: raise UserError(_("You can't cancel an order that is %s") % so.state) - sale_orders.action_cancel() + for so in sale_orders: + so.action_cancel() self.write({"partner_ref": False}) return super().button_cancel() diff --git a/purchase_sale_inter_company/models/purchase_order_line.py b/purchase_sale_inter_company/models/purchase_order_line.py index 13bad3eaa1b..2cc3979ae74 100644 --- a/purchase_sale_inter_company/models/purchase_order_line.py +++ b/purchase_sale_inter_company/models/purchase_order_line.py @@ -47,7 +47,7 @@ def create(self, vals_list): or self.env.user ) sale_lines = [] - for purchase_line in lines.filtered(lambda x: x.order_id == order): + for purchase_line in lines.filtered(lambda x, o=order: x.order_id == o): sale_lines.append( order._prepare_sale_order_line_data( purchase_line, @@ -102,7 +102,9 @@ def write(self, vals): { "order_line": [ (1, line.id, update_vals) - for line in sale_lines.filtered(lambda x: x.order_id == sale) + for line in sale_lines.filtered( + lambda x, s=sale: x.order_id == s + ) ] } ) diff --git a/purchase_sale_inter_company/readme/CONTRIBUTORS.md b/purchase_sale_inter_company/readme/CONTRIBUTORS.md index 88371203892..749ae1919da 100644 --- a/purchase_sale_inter_company/readme/CONTRIBUTORS.md +++ b/purchase_sale_inter_company/readme/CONTRIBUTORS.md @@ -12,3 +12,5 @@ - Pedro M. Baeza - \`Camptocamp \<\>\`: - Maksym Yankin \<\> +- \`Komit \<\>\`: + - Cuong Nguyen Mtm \<\> diff --git a/purchase_sale_inter_company/static/description/index.html b/purchase_sale_inter_company/static/description/index.html index 42a6054248f..f16b52c0877 100644 --- a/purchase_sale_inter_company/static/description/index.html +++ b/purchase_sale_inter_company/static/description/index.html @@ -1,4 +1,3 @@ - @@ -9,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -464,12 +464,18 @@

Contributors

  • Maksym Yankin <maksym.yankin@camptocamp.com>
  • +
  • `Komit <https://komit-consulting.com>`: +
  • Maintainers

    This module is maintained by the OCA.

    -Odoo Community Association + +Odoo Community Association +

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    diff --git a/purchase_sale_inter_company/tests/test_inter_company_purchase_sale.py b/purchase_sale_inter_company/tests/test_inter_company_purchase_sale.py index 9b0d4cd8a88..175f6b9c456 100644 --- a/purchase_sale_inter_company/tests/test_inter_company_purchase_sale.py +++ b/purchase_sale_inter_company/tests/test_inter_company_purchase_sale.py @@ -75,9 +75,42 @@ def setUpClass(cls): # Create purchase order cls.purchase_company_a = cls._create_purchase_order(cls.partner_company_b) - # Configure pricelist to USD - cls.env["product.pricelist"].sudo().search([]).write( - {"currency_id": cls.env.ref("base.USD").id} + # Create account + income_account = cls.env["account.account"].create( + { + "name": "test_account_income", + "code": "987", + "account_type": "income", + "company_id": cls.company_b.id, + } + ) + expense_account = cls.env["account.account"].create( + { + "name": "test account_expenses", + "code": "765", + "account_type": "expense", + "reconcile": True, + "company_id": cls.company_a.id, + } + ) + # Create journal + cls.env["account.journal"].create( + { + "name": "Customer Invoices - Test", + "code": "TEST1", + "type": "sale", + "company_id": cls.company_b.id, + "default_account_id": income_account.id, + } + ) + cls.env["account.journal"].create( + { + "name": "Vendor Bills - Test", + "code": "TEST2", + "type": "purchase", + "company_id": cls.company_a.id, + "default_account_id": expense_account.id, + } ) def _approve_po(self): @@ -162,6 +195,7 @@ def test_cancel_confirmed_po_so(self): self.purchase_company_a.with_user(self.user_company_a).button_cancel() def test_so_change_price(self): + self.company_b.sale_auto_validation = False sale = self._approve_po() sale.order_line.price_unit = 10 sale.action_confirm() @@ -182,6 +216,7 @@ def test_update_open_sale_order(self): When the purchase user request extra product, the sale order gets synched if it's open. """ + self.company_b.sale_auto_validation = False purchase = self.purchase_company_a sale = self._approve_po() sale.action_confirm() @@ -221,3 +256,74 @@ def test_update_open_sale_order(self): 3, "The quantity should decrease as it was in the purchase order", ) + + def test_default_intercompany_sale_user_id(self): + """ + When the intercompany_sale_user_id is not set, the current user that creates the + purchase order is used, this impacts the salesperson value on the sale order. + Following the _compute_user_id method on sale.order model, if there is no + salesperson set, the salesperson will be the user set on the Sale's customer, + or customer's company, or the current user if he is a salesman. + """ + self.company_b.intercompany_sale_user_id = False + self.company_b.sale_auto_validation = False + sale = self._approve_po() + self.assertEqual(sale.create_uid, self.user_company_a) + self.assertNotEqual(sale.user_id, self.user_company_b) + expected_salesperson = ( + sale.partner_id.user_id + or sale.partner_id.parent_id.user_id + or ( + self.user_company_a + if self.user_company_a.has_group("sales_team.group_sale_manager") + else False + ) + ) + self.assertNotEqual(sale.user_id, expected_salesperson) + + def test_sale_order_line_note_sync(self): + """ + When a purchase order line has a note, it should be copied to the sale order + line. + """ + self.purchase_company_a.order_line = [ + (0, 0, {"name": "Test Note", "display_type": "line_note", "product_qty": 0}) + ] + sale = self._approve_po() + self.assertEqual( + sale.order_line.filtered(lambda x: x.display_type == "line_note").name, + "Test Note", + ) + + def test_cannot_modify_pol_of_related_so_is_cancel(self): + """ + When the related sale order is cancel, the purchase order lines cannot be + created or modified. + """ + self.company_b.sale_auto_validation = False + sale = self._approve_po() + sale.action_confirm() + purchase_line = self.purchase_company_a.order_line + sale._action_cancel() + with self.assertRaises(UserError): + purchase_line[0].product_qty = 5 + with self.assertRaises(UserError): + self.env["purchase.order.line"].create( + { + "order_id": self.purchase_company_a.id, + "product_id": self.service_product_2.id, + "product_qty": 5, + "name": "Test", + } + ) + sale.action_draft() + sale.action_confirm() + purchase_line[0].product_qty = 5 + self.env["purchase.order.line"].create( + { + "order_id": self.purchase_company_a.id, + "product_id": self.service_product_2.id, + "product_qty": 5, + "name": "Test", + } + ) diff --git a/purchase_sale_inter_company/views/res_config_view.xml b/purchase_sale_inter_company/views/res_config_view.xml index b77c0c3b750..2a42c9c5c39 100644 --- a/purchase_sale_inter_company/views/res_config_view.xml +++ b/purchase_sale_inter_company/views/res_config_view.xml @@ -7,32 +7,34 @@ ref="account_invoice_inter_company.res_config_settings_view_form" /> - -
    Purchase/Sale
    -
    - -
    -
    -