From 54eb69d6c31cd73e928cd08fec10237742e85993 Mon Sep 17 00:00:00 2001
From: daniquilez <dani.quilez@gmail.com>
Date: Mon, 10 Mar 2025 15:17:16 +0100
Subject: [PATCH] =?UTF-8?q?[IMP]=20=E2=9C=A8=20Metadata=20strategy=20on=20?=
 =?UTF-8?q?sale=20order=20contract=20activation?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../__manifest__.py                           |  1 +
 .../components/contract_utils.py              | 64 ++++++++++++-------
 .../components/sale_order_utils.py            | 58 +++++------------
 .../models/pack_type_mixin.py                 |  1 +
 .../models/sale_order.py                      | 24 +++----
 .../views/sale_order_views.xml                |  3 -
 .../service_invoicing_action_create.py        | 17 +++--
 7 files changed, 81 insertions(+), 87 deletions(-)

diff --git a/energy_communities_service_invoicing/__manifest__.py b/energy_communities_service_invoicing/__manifest__.py
index 1a6ac870a..f7b8a1d59 100644
--- a/energy_communities_service_invoicing/__manifest__.py
+++ b/energy_communities_service_invoicing/__manifest__.py
@@ -15,6 +15,7 @@
         "base",
         "contract",
         "sale",
+        "sale_order_metadata",
         "sales_team",
         "purchase",
         "product",
diff --git a/energy_communities_service_invoicing/components/contract_utils.py b/energy_communities_service_invoicing/components/contract_utils.py
index bd18f5196..181c63508 100644
--- a/energy_communities_service_invoicing/components/contract_utils.py
+++ b/energy_communities_service_invoicing/components/contract_utils.py
@@ -5,6 +5,20 @@ class ContractUtils(Component):
     _inherit = "contract.utils"
 
     def setup_initial_data(self):
+        self._set_configuration_journal_if_defined()
+        self._set_start_date(self.work.record.sale_order_id.commitment_date)
+        if "discount" in self.work.record.sale_order_id.metadata_line_ids.mapped("key"):
+            self._set_discount(
+                self.work.record.sale_order_id.get_metadata_value("discount")
+            )
+        contract_update_dict = {"status": "paused"}
+        for contract_update_data in self.work.record.sale_order_id.metadata_line_ids:
+            if contract_update_data.key not in ["discount"]:
+                value = contract_update_data.value
+                # TODO: Not a very robust condition. Assuming all Many2one fields are defined with _id at the end
+                if "_id" in contract_update_data.key:
+                    value = int(contract_update_data.value)
+                contract_update_dict[contract_update_data.key] = value
         for line in self.work.record.contract_line_ids:
             line.write(
                 {
@@ -15,7 +29,24 @@ class ContractUtils(Component):
                     "quantity": 0,
                 }
             )
-        self.work.record.write({"status": "paused"})
+        self.work.record.write(contract_update_dict)
+
+    def _set_start_date(self, date_start):
+        self.work.record.write({"date_start": date_start})
+        for line in self.work.record.contract_line_ids:
+            line.write({"date_start": date_start})
+            line._compute_state()
+
+    def _set_discount(self, discount):
+        for line in self.work.record.contract_line_ids:
+            line.write({"discount": discount})
+
+    # method to be extended if using component for another pack_type
+    def _set_configuration_journal_if_defined(self):
+        if self.work.record.pack_type == "platform_pack":
+            journal_id = self.work.record.company_id.service_invoicing_sale_journal_id
+            if journal_id:
+                self.work.record.write({"journal_id": journal_id.id})
 
     def _activate_contract_lines(self, execution_date):
         for line in self.work.record.contract_line_ids:
@@ -34,7 +65,7 @@ class ContractUtils(Component):
 
     def set_contract_status_active(self, execution_date):
         self._activate_contract_lines(execution_date)
-        self.set_start_date(execution_date)
+        self._set_start_date(execution_date)
         self.work.record.write({"status": "in_progress"})
 
     def set_contract_status_closed(self, execution_date):
@@ -45,23 +76,6 @@ class ContractUtils(Component):
             line._compute_state()
         self.work.record.set_close_status_type_by_date()
 
-    def set_start_date(self, date_start):
-        self.work.record.write({"date_start": date_start})
-        for line in self.work.record.contract_line_ids:
-            line.write({"date_start": date_start})
-            line._compute_state()
-
-    def set_discount(self, discount):
-        for line in self.work.record.contract_line_ids:
-            line.write({"discount": discount})
-
-    # method to be extended if using component for another pack_type
-    def set_configuration_journal_if_defined(self):
-        if self.work.record.pack_type == "platform_pack":
-            journal_id = self.work.record.company_id.service_invoicing_sale_journal_id
-            if journal_id:
-                self.work.record.write({"journal_id": journal_id.id})
-
     def clean_non_service_lines(self):
         for line in self.work.record.contract_line_ids:
             if not self._is_service_line(line):
@@ -141,7 +155,6 @@ class ContractUtils(Component):
         executed_action_description_list = executed_action_description.split(",")
         return {
             "company_id": self.work.record.partner_id.related_company_id,
-            "community_company_id": self.work.record.community_company_id,
             "pack_id": pack_id
             if "modify_pack" in executed_action_description_list
             else self.work.record.pack_id,
@@ -154,9 +167,14 @@ class ContractUtils(Component):
             "start_date": execution_date,
             "executed_action": executed_action,
             "executed_action_description": executed_action_description,
-            "discount": discount
-            if "modify_discount" in executed_action_description_list
-            else self.work.record.discount,
+            "metadata": {
+                "community_company_id": self.work.record.community_company_id.id
+                if self.work.record.community_company_id
+                else False,
+                "discount": discount
+                if "modify_discount" in executed_action_description_list
+                else self.work.record.discount,
+            },
         }
 
     def _is_service_line(self, contract_line):
diff --git a/energy_communities_service_invoicing/components/sale_order_utils.py b/energy_communities_service_invoicing/components/sale_order_utils.py
index e3e241ddc..460a084b1 100644
--- a/energy_communities_service_invoicing/components/sale_order_utils.py
+++ b/energy_communities_service_invoicing/components/sale_order_utils.py
@@ -5,21 +5,21 @@ from odoo.addons.energy_communities.utils import contract_utils
 class SaleOrderUtils(Component):
     _inherit = "sale.order.utils"
 
-    def create_service_invoicing_sale_order(
+    def _create_service_invoicing_sale_order(
         self,
         company_id,
-        community_company_id,
         pack_id,
         pricelist_id,
         payment_mode_id,
         start_date,
         executed_action,
         executed_action_description,
+        metadata,
     ):
         so_creation_dict = {
             "partner_id": company_id.partner_id.id,
-            # "company_id": company_id.id,
-            "community_company_id": community_company_id.id,
+            "company_id": self.env.company.id,
+            "commitment_date": start_date,
             "pricelist_id": pricelist_id.id,
             "service_invoicing_action": executed_action,
             "service_invoicing_action_description": executed_action_description,
@@ -42,70 +42,46 @@ class SaleOrderUtils(Component):
             so_creation_dict[
                 "team_id"
             ] = self.env.company.service_invoicing_sale_team_id.id
+        if metadata:
+            metadata_list = []
+            for meta_key in metadata.keys():
+                metadata_list.append(
+                    (0, 0, {"key": meta_key, "value": metadata[meta_key]})
+                )
+            so_creation_dict["metadata_line_ids"] = metadata_list
         sale_order = self.env["sale.order"].create(so_creation_dict)
         # Trigger name computattion in oder to include product's description_sale
         for order_line in sale_order.order_line:
             order_line._compute_name()
         return sale_order
 
-    def _create_service_invoicing(
-        self,
-        company_id,
-        community_company_id,
-        pack_id,
-        pricelist_id,
-        payment_mode_id,
-        start_date,
-        discount,
-        executed_action,
-        executed_action_description="none",
-    ):
-        so = self.create_service_invoicing_sale_order(
-            company_id,
-            community_company_id,
-            pack_id,
-            pricelist_id,
-            payment_mode_id,
-            start_date,
-            executed_action,
-            executed_action_description,
-        )
-        so.action_confirm()
-        service_invoicing_id = self._get_related_contracts(so)
-        # TODO: We must call contract_utils with a better component and workcontext modification approach
-        with contract_utils(self.env, service_invoicing_id) as component:
-            component.clean_non_service_lines()
-            component.set_start_date(start_date)
-            component.set_discount(discount)
-            component.set_configuration_journal_if_defined()
-        return service_invoicing_id
-
     def create_service_invoicing_initial(
         self,
         company_id,
-        community_company_id,
         pack_id,
         pricelist_id,
         start_date,
-        discount,
         executed_action,
         executed_action_description="none",
         payment_mode_id=False,
+        metadata=False,
     ):
-        service_invoicing_id = self._create_service_invoicing(
+        so = self._create_service_invoicing_sale_order(
             company_id,
-            community_company_id,
             pack_id,
             pricelist_id,
             payment_mode_id,
             start_date,
-            discount,
             executed_action,
             executed_action_description,
+            metadata,
         )
+        so.action_confirm()
+        service_invoicing_id = self._get_related_contracts(so)
         # TODO: We must call contract_utils with a better component and workcontext modification approach
         with contract_utils(self.env, service_invoicing_id) as component:
             component.setup_initial_data()
+            component.clean_non_service_lines()
             if service_invoicing_id.is_free_pack:
                 component.set_contract_status_active(start_date)
         return service_invoicing_id
diff --git a/energy_communities_service_invoicing/models/pack_type_mixin.py b/energy_communities_service_invoicing/models/pack_type_mixin.py
index 7d3ce9e2a..786ec9561 100644
--- a/energy_communities_service_invoicing/models/pack_type_mixin.py
+++ b/energy_communities_service_invoicing/models/pack_type_mixin.py
@@ -13,6 +13,7 @@ class PackTypeMixin(models.AbstractModel):
         compute_sudo=True,
         string="Pack Type",
         store=True,
+        default="none",
     )
 
     def _get_pack_type_from_product_category(self, pack_type, category_id):
diff --git a/energy_communities_service_invoicing/models/sale_order.py b/energy_communities_service_invoicing/models/sale_order.py
index ad4b23c5a..67447ae36 100644
--- a/energy_communities_service_invoicing/models/sale_order.py
+++ b/energy_communities_service_invoicing/models/sale_order.py
@@ -7,12 +7,6 @@ class SaleOrder(models.Model):
     _name = "sale.order"
     _inherit = "sale.order"
 
-    community_company_id = fields.Many2one(
-        "res.company",
-        string="Related community",
-        domain="[('hierarchy_level','=','community')]",
-    )
-
     service_invoicing_action = fields.Selection(
         selection=_SALE_ORDER_SERVICE_INVOICING_ACTION_VALUES,
         required=True,
@@ -26,16 +20,14 @@ class SaleOrder(models.Model):
 
     def action_create_contract(self):
         contracts = super().action_create_contract()
-        if self.community_company_id:
-            for contract in contracts:
-                contract.write(
-                    {
-                        "community_company_id": self.community_company_id.id,
-                        "pricelist_id": self.pricelist_id.id,
-                        "payment_mode_id": self.payment_mode_id.id,
-                        "sale_order_id": self.id,
-                    }
-                )
+        for contract in contracts:
+            contract.write(
+                {
+                    "pricelist_id": self.pricelist_id.id,
+                    "payment_mode_id": self.payment_mode_id.id,
+                    "sale_order_id": self.id,
+                }
+            )
         return contracts
 
     def action_show_contracts(self):
diff --git a/energy_communities_service_invoicing/views/sale_order_views.xml b/energy_communities_service_invoicing/views/sale_order_views.xml
index 72c636d92..632add91b 100644
--- a/energy_communities_service_invoicing/views/sale_order_views.xml
+++ b/energy_communities_service_invoicing/views/sale_order_views.xml
@@ -11,9 +11,6 @@
             attrs="{'readonly': 1,'invisible': [('service_invoicing_action','not in', ['modification','activate'])]}"
           />
         </xpath>
-        <xpath expr="//field[@name='partner_id']" position="after">
-          <field name="community_company_id" />
-        </xpath>
         <xpath expr="//field[@name='company_id']" position="attributes">
           <attribute name="required">0</attribute>
         </xpath>
diff --git a/energy_communities_service_invoicing/wizards/service_invoicing_action_create.py b/energy_communities_service_invoicing/wizards/service_invoicing_action_create.py
index fd06a8e04..d0c803047 100644
--- a/energy_communities_service_invoicing/wizards/service_invoicing_action_create.py
+++ b/energy_communities_service_invoicing/wizards/service_invoicing_action_create.py
@@ -57,7 +57,9 @@ class ServiceInvoicingActionCreateWizard(models.TransientModel):
         store=False,
     )
     platform_pack_product_categ_id = fields.Many2one(
-        "product.category", compute="_compute_platform_pack_product_categ_id", store=False
+        "product.category",
+        compute="_compute_platform_pack_product_categ_id",
+        store=False,
     )
 
     def _compute_platform_pack_product_categ_id(self):
@@ -126,16 +128,19 @@ class ServiceInvoicingActionCreateWizard(models.TransientModel):
         # If none of previous create a new contract
         else:
             with sale_order_utils(self.env) as component:
+                # TODO: pass community_company_id as metadata
                 service_invoicing_id = component.create_service_invoicing_initial(
                     company_id,
-                    community_company_id,
                     self.platform_pack_id,
                     self.pricelist_id,
                     self.execution_date,
-                    self.discount,
                     "activate",
                     "active_platform_service_invocing",
                     payment_mode_id,
+                    {
+                        "community_company_id": community_company_id.id,
+                        "discount": self.discount,
+                    },
                 )
         return service_invoicing_id
 
@@ -182,7 +187,11 @@ class ServiceInvoicingActionCreateWizard(models.TransientModel):
         # Check if already open one and raise error
         for record in impacted_records:
             existing_contract = get_existing_open_pack_contract(
-                self.env, record.parent_id.partner_id, "platform_pack", contract_id=False, custom_query=[("community_company_id", "=", record.id)]
+                self.env,
+                record.parent_id.partner_id,
+                "platform_pack",
+                contract_id=False,
+                custom_query=[("community_company_id", "=", record.id)],
             )
 
             if existing_contract:
-- 
GitLab