From a3568be8d0c9e469f396ed53d5423b4ce28f4205 Mon Sep 17 00:00:00 2001 From: "chafique.delli" Date: Fri, 14 Oct 2022 12:53:57 +0200 Subject: [PATCH] [14.0][IMP] purchase_sale_inter_company: the sale order is updated when the purchase order is modified --- purchase_sale_inter_company/README.rst | 2 +- purchase_sale_inter_company/__manifest__.py | 2 + .../models/purchase_order.py | 44 ++++++-- .../static/description/index.html | 3 +- .../tests/test_inter_company_purchase_sale.py | 103 ++++-------------- .../views/purchase_view.xml | 17 +++ 6 files changed, 77 insertions(+), 94 deletions(-) create mode 100644 purchase_sale_inter_company/views/purchase_view.xml diff --git a/purchase_sale_inter_company/README.rst b/purchase_sale_inter_company/README.rst index 6f12bcc1547..93c0bd47456 100644 --- a/purchase_sale_inter_company/README.rst +++ b/purchase_sale_inter_company/README.rst @@ -7,7 +7,7 @@ Inter Company Module for Purchase to Sale Order !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:3899bc2db53f1d1d16a8c0d9b0f75002813b2e3095815b55949efad59958f1a3 + !! source digest: sha256:ed23c6c7f375be3c7730c810d0af05c1373ef8d8dbbde6e793b16b999f97979d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/purchase_sale_inter_company/__manifest__.py b/purchase_sale_inter_company/__manifest__.py index 745bb8bf37d..ac13e802fb0 100644 --- a/purchase_sale_inter_company/__manifest__.py +++ b/purchase_sale_inter_company/__manifest__.py @@ -17,9 +17,11 @@ "sale_stock", "purchase_stock", "account_invoice_inter_company", + "base_view_inheritance_extension", ], "data": [ "views/res_config_view.xml", + "views/purchase_view.xml", "wizard/stock_backorder_confirmation_views.xml", ], "demo": [ diff --git a/purchase_sale_inter_company/models/purchase_order.py b/purchase_sale_inter_company/models/purchase_order.py index bdef2e870f8..e354cd6d5f7 100644 --- a/purchase_sale_inter_company/models/purchase_order.py +++ b/purchase_sale_inter_company/models/purchase_order.py @@ -16,11 +16,12 @@ class PurchaseOrder(models.Model): compute_sudo=True, ) + @api.depends("state") def _compute_intercompany_sale_order_id(self): """A One2many would be simpler, but the record rules make unaccesible for regular users so the logic doesn't work properly""" ids_dict_list = self.env["sale.order"].search_read( - [("auto_purchase_order_id", "in", self.ids)], + [("auto_purchase_order_id", "in", self.ids), ("state", "!=", "cancel")], ["id", "auto_purchase_order_id"], ) ids_dict = {d["auto_purchase_order_id"][0]: d["id"] for d in ids_dict_list} @@ -192,16 +193,33 @@ def _prepare_sale_order_line_data(self, purchase_line, dest_company, sale_order) return new_line._convert_to_write(new_line._cache) def button_cancel(self): - sale_orders = ( - self.env["sale.order"] - .sudo() - .search([("auto_purchase_order_id", "in", self.ids)]) - ) - 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() - self.write({"partner_ref": False}) + if self.intercompany_sale_order_id: + if self.intercompany_sale_order_id.sudo().state not in [ + "draft", + "sent", + "cancel", + ]: + raise UserError( + _( + "You can not cancel your purchase order %s.\n" + "The sale order %s at your supplier %s that is linked " + "to your purchase order, is in the state %s.\n" + "In order to cancel your purchase order, you must first " + "ask your supplier to cancel his sale order." + ) + % ( + self.name, + self.intercompany_sale_order_id.sudo().name, + self.partner_id.name, + self.intercompany_sale_order_id.sudo().state, + ) + ) + if self.intercompany_sale_order_id.sudo().state in [ + "draft", + "sent", + ]: + self.intercompany_sale_order_id.sudo().action_cancel() + self.write({"partner_ref": False}) return super().button_cancel() @@ -214,11 +232,13 @@ class PurchaseOrderLine(models.Model): compute_sudo=True, ) + @api.depends("state") def _compute_intercompany_sale_line_id(self): """A One2many would be simpler, but the record rules make unaccesible for regular users so the logic doesn't work properly""" ids_dict_list = self.env["sale.order.line"].search_read( - [("auto_purchase_line_id", "in", self.ids)], ["id", "auto_purchase_line_id"] + [("auto_purchase_line_id", "in", self.ids), ("state", "!=", "cancel")], + ["id", "auto_purchase_line_id"], ) ids_dict = {d["auto_purchase_line_id"][0]: d["id"] for d in ids_dict_list} for line in self: diff --git a/purchase_sale_inter_company/static/description/index.html b/purchase_sale_inter_company/static/description/index.html index 8964e2a90f9..d7a34d79ac2 100644 --- a/purchase_sale_inter_company/static/description/index.html +++ b/purchase_sale_inter_company/static/description/index.html @@ -1,3 +1,4 @@ + @@ -366,7 +367,7 @@

Inter Company Module for Purchase to Sale Order

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:3899bc2db53f1d1d16a8c0d9b0f75002813b2e3095815b55949efad59958f1a3 +!! source digest: sha256:ed23c6c7f375be3c7730c810d0af05c1373ef8d8dbbde6e793b16b999f97979d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/multi-company Translate me on Weblate Try me on Runboat

This module is useful if there are multiple companies in the same Odoo database and those companies sell goods or services among themselves.

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 d253a374354..18a197b22c4 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 @@ -3,7 +3,6 @@ # Copyright 2018-2019 Tecnativa - Carlos Dauden # Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -import re from odoo.exceptions import UserError from odoo.tests.common import Form @@ -194,7 +193,12 @@ def _approve_po(self, purchase_id): return ( self.env["sale.order"] .with_user(self.user_company_b) - .search([("auto_purchase_order_id", "=", purchase_id.id)]) + .search( + [ + ("auto_purchase_order_id", "=", purchase_id.id), + ("state", "!=", "cancel"), + ] + ) ) def test_purchase_sale_inter_company(self): @@ -519,81 +523,20 @@ def test_sync_picking_different_product_multiple_lines(self): sale.sudo().write({"picking_ids": [(4, new_picking.id)]}) sale.action_confirm() - def test_update_open_sale_order(self): - """ - When the purchase user request extra product, the sale order gets synched if - it's open. - """ - purchase = self._create_purchase_order( - self.partner_company_b, self.consumable_product - ) - purchase.picking_type_id = self.warehouse_a.in_type_id - sale = self._approve_po(purchase) - sale.action_confirm() - # Now we add an extra product to the PO and it will show up in the SO - po_form = Form(purchase) - with po_form.order_line.new() as line: - line.product_id = self.consumable_product_2 - line.product_qty = 6 - po_form.save() - # It's synched and the values match - synched_order_line = sale.order_line.filtered( - lambda x: x.product_id == self.consumable_product_2 - ) - self.assertTrue( - bool(synched_order_line), - "The line should have been created in the sale order", - ) - self.assertEqual( - synched_order_line.product_uom_qty, - 6, - "The quantity should be equal to the one set in the purchase order", - ) - # Also the moves match as well - so_picking_id = sale.picking_ids - synched_move = so_picking_id.move_lines.filtered( - lambda x: x.product_id == self.consumable_product_2 - ) - self.assertTrue( - bool(synched_move), - "The move should have been created in the delivery order", - ) - self.assertEqual( - synched_move.product_uom_qty, - 6, - "The quantity should be equal to the one set in the purchase order", - ) - # The quantity is synched as well - purchase_line = purchase.order_line.filtered( - lambda x: x.product_id == self.consumable_product_2 - ).sudo() - purchase_line.product_qty = 8 - self.assertEqual( - synched_order_line.product_uom_qty, - 8, - "The quantity should be equal to the one set in the purchase order", - ) - self.assertEqual( - synched_move.product_uom_qty, - 8, - "The quantity should synched to the one set in the purchase order", - ) - # Let's decrease the quantity - purchase_line.product_qty = 3 - self.assertEqual( - synched_order_line.product_uom_qty, - 3, - "The quantity should decrease as it was in the purchase order", - ) - self.assertEqual( - synched_move.product_uom_qty, - 8, - "The quantity should remain as it was as it can't be decreased from the SO", - ) - # A warning activity is scheduled in the picking - self.assertRegex( - so_picking_id.activity_ids.note, - re.compile( - "3.0 Units of Consumable Product 2.+instead of 8.0 Units", re.DOTALL - ), - ) + def test_update_po(self): + # create intercompany sale order + self.company_b.sale_auto_validation = False + old_sale = self._approve_po(self.purchase_company_a) + # cancel and back to draft the PO before update + self.purchase_company_a.button_cancel() + self.purchase_company_a.button_draft() + # update PO + self.purchase_company_a.order_line.product_qty = 5.0 + # create new intercompany sale order after confirm updated PO + self.company_b.sale_auto_validation = True + new_sale = self._approve_po(self.purchase_company_a) + # test update + self.assertEqual(new_sale.order_line.product_uom_qty, 5.0) + self.assertEqual(new_sale.state, "sale") + self.assertEqual(self.purchase_company_a.intercompany_sale_order_id, new_sale) + self.assertEqual(old_sale.auto_purchase_order_id, self.purchase_company_a) diff --git a/purchase_sale_inter_company/views/purchase_view.xml b/purchase_sale_inter_company/views/purchase_view.xml new file mode 100644 index 00000000000..ff74f1b4142 --- /dev/null +++ b/purchase_sale_inter_company/views/purchase_view.xml @@ -0,0 +1,17 @@ + + + + purchase.order + + + + + + + + ['|', ('state', 'in', ('done', 'cancel')), '&', ('intercompany_sale_order_id', '!=', False), ('state', '=', 'purchase')] + + + + +