From de302ad8c40ef0c58a44db5ec07ad32a4a1af19e Mon Sep 17 00:00:00 2001 From: daniquilez <dani.quilez@gmail.com> Date: Wed, 26 Feb 2025 14:45:03 +0100 Subject: [PATCH] =?UTF-8?q?[IMP]=20=E2=9C=A8=20Batch=20create=20service=20?= =?UTF-8?q?invoicings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- energy_communities/views/res_users_view.xml | 50 +++--- .../__manifest__.py | 1 + .../components/sale_order_utils.py | 3 + .../models/__init__.py | 1 - .../models/contract.py | 2 +- .../models/res_company.py | 8 + .../models/service_invoicing_info_mixin.py | 28 ---- energy_communities_service_invoicing/utils.py | 26 +++- .../views/res_company_views.xml | 13 ++ .../wizards/service_invoicing_action.py | 10 +- .../service_invoicing_action_create.py | 146 ++++++++++++++---- .../service_invoicing_action_create.xml | 24 ++- 12 files changed, 212 insertions(+), 100 deletions(-) delete mode 100644 energy_communities_service_invoicing/models/service_invoicing_info_mixin.py diff --git a/energy_communities/views/res_users_view.xml b/energy_communities/views/res_users_view.xml index 9eaba37a8..7cb910ae9 100644 --- a/energy_communities/views/res_users_view.xml +++ b/energy_communities/views/res_users_view.xml @@ -1,40 +1,28 @@ <?xml version="1.0" encoding="utf-8" ?> <odoo> <data noupdate="1"> - <record model="ir.actions.server" id="print_instance"> - <field name="name">Push user to Keycloak</field> - <field name="model_id" ref="model_res_users" /> - <field name="binding_model_id" ref="model_res_users" /> - <field name="binding_type">action</field> - <field name="groups_id" eval="[(4,ref('group_platform_manager'))]" /> - <field name="state">code</field> - <field name="code"> - record.create_users_on_keycloak() - </field> - </record> - - <record id="view_res_users_form_inherit" model="ir.ui.view"> - <field name="name">res.users.form.inherit</field> - <field name="model">res.users</field> - <field name="inherit_id" ref="base.view_users_form" /> - <field name="arch" type="xml"> + <record id="view_res_users_form_inherit" model="ir.ui.view"> + <field name="name">res.users.form.inherit</field> + <field name="model">res.users</field> + <field name="inherit_id" ref="base.view_users_form" /> + <field name="arch" type="xml"> <xpath - expr="//notebook//field[@name='role_line_ids']/tree//field[@name='role_id']" - position="attributes" - > - <attribute name="domain" /> + expr="//notebook//field[@name='role_line_ids']/tree//field[@name='role_id']" + position="attributes" + > + <attribute name="domain" /> </xpath> - </field> - </record> - <record id="view_res_users_form_inherit_oauth" model="ir.ui.view"> - <field name="name">res.users.form.inherit.oauth</field> - <field name="model">res.users</field> - <field name="inherit_id" ref="auth_oauth.view_users_form" /> - <field name="arch" type="xml"> + </field> + </record> + <record id="view_res_users_form_inherit_oauth" model="ir.ui.view"> + <field name="name">res.users.form.inherit.oauth</field> + <field name="model">res.users</field> + <field name="inherit_id" ref="auth_oauth.view_users_form" /> + <field name="arch" type="xml"> <field name="oauth_access_token" position="after"> - <field name="last_user_invitation_through_kc" /> + <field name="last_user_invitation_through_kc" /> </field> - </field> - </record> + </field> + </record> </data> </odoo> diff --git a/energy_communities_service_invoicing/__manifest__.py b/energy_communities_service_invoicing/__manifest__.py index a3ec60b9e..f525cf563 100644 --- a/energy_communities_service_invoicing/__manifest__.py +++ b/energy_communities_service_invoicing/__manifest__.py @@ -15,6 +15,7 @@ "base", "contract", "sale", + "sales_team", "purchase", "product", "product_contract", diff --git a/energy_communities_service_invoicing/components/sale_order_utils.py b/energy_communities_service_invoicing/components/sale_order_utils.py index fca1c7d84..5cfeeccaa 100644 --- a/energy_communities_service_invoicing/components/sale_order_utils.py +++ b/energy_communities_service_invoicing/components/sale_order_utils.py @@ -36,6 +36,9 @@ class SaleOrderUtils(Component): ) ], } + # Apply configuration sales team to service invoicing sales order + if company_id.service_invoicing_sale_team_id: + so_creation_dict["team_id"] = company_id.service_invoicing_sale_team_id.id 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: diff --git a/energy_communities_service_invoicing/models/__init__.py b/energy_communities_service_invoicing/models/__init__.py index 4c3afbbec..7ba9edcc6 100644 --- a/energy_communities_service_invoicing/models/__init__.py +++ b/energy_communities_service_invoicing/models/__init__.py @@ -1,4 +1,3 @@ -from . import service_invoicing_info_mixin from . import abstract_contract from . import account_move from . import contract diff --git a/energy_communities_service_invoicing/models/contract.py b/energy_communities_service_invoicing/models/contract.py index 392880e0a..14932d2aa 100644 --- a/energy_communities_service_invoicing/models/contract.py +++ b/energy_communities_service_invoicing/models/contract.py @@ -108,7 +108,7 @@ class ContractContract(models.Model): if record.community_company_id: existing_contract = record._get_existing_same_open_contract() if existing_contract: - raise_existing_same_open_contract_error() + raise_existing_same_open_contract_error(existing_contract) def _compute_received_invoices_count(self): for record in self: diff --git a/energy_communities_service_invoicing/models/res_company.py b/energy_communities_service_invoicing/models/res_company.py index 11701aaea..1c74ab3bd 100644 --- a/energy_communities_service_invoicing/models/res_company.py +++ b/energy_communities_service_invoicing/models/res_company.py @@ -10,3 +10,11 @@ class ResCompany(models.Model): comodel_name="account.journal", string="Service invoicing journal", ) + service_invoicing_payment_mode_id = fields.Many2one( + comodel_name="account.payment.mode", + string="Service invoicing payment mode", + ) + service_invoicing_sale_team_id = fields.Many2one( + comodel_name="crm.team", + string="Service invoicing sales team", + ) diff --git a/energy_communities_service_invoicing/models/service_invoicing_info_mixin.py b/energy_communities_service_invoicing/models/service_invoicing_info_mixin.py deleted file mode 100644 index a1bb3b721..000000000 --- a/energy_communities_service_invoicing/models/service_invoicing_info_mixin.py +++ /dev/null @@ -1,28 +0,0 @@ -from odoo import api, fields, models - - -class ServiceInvoicingInfoMixin(models.AbstractModel): - _name = "service.invoicing.info.mixin" - _description = "Get info about current service invoicing configuration" - - pack_product_product_ids = fields.Many2many( - comodel_name="product.product", - _compute="_compute_pack_product_product_ids", - store=False, - ) - - @api.depends("name") - def _compute_pack_product_product_ids(self): - for record in self: - pack_product_product_ids = [] - record.pack_product_product_ids = self.env["product.product"].search( - [ - ( - "categ_id", - "=", - self.env.ref( - "energy_communities_service_invoicing.product_category_pack" - ).id, - ) - ] - ) diff --git a/energy_communities_service_invoicing/utils.py b/energy_communities_service_invoicing/utils.py index 3da795640..e9d5e6d38 100644 --- a/energy_communities_service_invoicing/utils.py +++ b/energy_communities_service_invoicing/utils.py @@ -21,7 +21,25 @@ _SALE_ORDER_SERVICE_INVOICING_ACTION_VALUES = [ ] + _SERVICE_INVOICING_EXECUTED_ACTION_VALUES[:-1] -def service_invoicing_view(env: Environment, service_invoicing_id: ContractContract): +def service_invoicing_tree_view(env: Environment): + return { + "type": "ir.actions.act_window", + "res_model": "contract.contract", + "views": [ + ( + env.ref( + "energy_communities_service_invoicing.view_service_invoicing_tree" + ).id, + "form", + ), + ], + "target": "current", + } + + +def service_invoicing_form_view_for_platform_admins( + env: Environment, service_invoicing_id: ContractContract +): return { "type": "ir.actions.act_window", "res_model": "contract.contract", @@ -39,9 +57,11 @@ def service_invoicing_view(env: Environment, service_invoicing_id: ContractContr # TODO: Think a bit more about more about if this 3 methods must go to contract utils component -def raise_existing_same_open_contract_error(): +def raise_existing_same_open_contract_error(existing_contract): raise ValidationError( - _("It can only exists one service contract per Customer and related community.") + _( + "It already exists an open contract ({}) with same company and community." + ).format(existing_contract.name) ) diff --git a/energy_communities_service_invoicing/views/res_company_views.xml b/energy_communities_service_invoicing/views/res_company_views.xml index a907bb966..3b5673954 100644 --- a/energy_communities_service_invoicing/views/res_company_views.xml +++ b/energy_communities_service_invoicing/views/res_company_views.xml @@ -1,4 +1,15 @@ <odoo> + <record id="service_invoicing_action_create_wizard_from_company_action" model="ir.actions.server"> + <field name="name">Assign pack to community</field> + <field name="binding_model_id" ref="model_res_company" /> + <field name="model_id" ref="model_service_invoicing_action_create_wizard" /> + <field name="binding_type">action</field> + <field name="state">code</field> + <field name="groups_id" eval="[(4,ref('energy_communities.group_platform_manager'))]" /> + <field name="code"> + action = model.get_service_invoicing_action_create_wizard_form_view() + </field> + </record> <record id="view_service_invocing_company_form" model="ir.ui.view"> <field name="name">service.invoicing.res.company.form.inherit</field> <field name="model">res.company</field> @@ -9,6 +20,8 @@ <group> <field name="id" invisible="1"/> <field name="service_invoicing_journal_id" domain="[('company_id', '=', id)]" /> + <field name="service_invoicing_payment_mode_id" domain="[('company_id', '=', id)]" /> + <field name="service_invoicing_sale_team_id" domain="[('company_id', '=', id)]" /> </group> </page> </xpath> diff --git a/energy_communities_service_invoicing/wizards/service_invoicing_action.py b/energy_communities_service_invoicing/wizards/service_invoicing_action.py index 49c7ed275..ec3423774 100644 --- a/energy_communities_service_invoicing/wizards/service_invoicing_action.py +++ b/energy_communities_service_invoicing/wizards/service_invoicing_action.py @@ -6,7 +6,7 @@ from odoo.addons.energy_communities.utils import contract_utils from ..utils import ( _SERVICE_INVOICING_EXECUTED_ACTION_VALUES, - service_invoicing_view, + service_invoicing_form_view_for_platform_admins, ) @@ -46,7 +46,9 @@ class ServiceInvoicingActionWizard(models.TransientModel): self.discount, self.payment_mode_id, ) - return service_invoicing_view(self.env, service_invoicing_id) + return service_invoicing_form_view_for_platform_admins( + self.env, service_invoicing_id + ) def execute_reopen(self): with contract_utils(self.env, self.service_invoicing_id) as component: @@ -57,7 +59,9 @@ class ServiceInvoicingActionWizard(models.TransientModel): self.discount, self.payment_mode_id, ) - return service_invoicing_view(self.env, service_invoicing_id) + return service_invoicing_form_view_for_platform_admins( + self.env, service_invoicing_id + ) def _validate_execute_modify(self): if ( 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 a68cfef60..33a67f2a1 100644 --- a/energy_communities_service_invoicing/wizards/service_invoicing_action_create.py +++ b/energy_communities_service_invoicing/wizards/service_invoicing_action_create.py @@ -13,14 +13,15 @@ from ..utils import ( get_existing_last_closed_contract, get_existing_open_contract, raise_existing_same_open_contract_error, - service_invoicing_view, + service_invoicing_form_view_for_platform_admins, + service_invoicing_tree_view, ) class ServiceInvoicingActionCreateWizard(models.TransientModel): _name = "service.invoicing.action.create.wizard" _description = "Create service invoicing for an energy community" - _inherit = ["user.currentcompany.mixin", "service.invoicing.info.mixin"] + _inherit = ["user.currentcompany.mixin"] company_id = fields.Many2one("res.company", string="Coordinator") community_company_id = fields.Many2one( @@ -28,11 +29,12 @@ class ServiceInvoicingActionCreateWizard(models.TransientModel): string="Community", domain="[('id', 'in', allowed_community_company_ids)]", ) + community_company_mids = fields.Many2many( + comodel_name="res.company", + ) service_pack_id = fields.Many2one( "product.product", string="Service pack", - domain="[('id', 'in', pack_product_product_ids)]", - precompute=True, ) payment_mode_id = fields.Many2one( "account.payment.mode", @@ -49,43 +51,67 @@ class ServiceInvoicingActionCreateWizard(models.TransientModel): ) allowed_payment_mode_ids = fields.Many2many( comodel_name="account.payment.mode", - _compute="_compute_ allowed_payment_mode_ids", + _compute="_compute_allowed_payment_mode_ids", store=False, ) + pack_product_categ_id = fields.Many2one( + "product.category", compute="_compute_pack_product_categ_id", store=False + ) - @api.depends("company_id") + def _compute_pack_product_categ_id(self): + for record in self: + record.pack_product_categ_id = self.env.ref( + "energy_communities_service_invoicing.product_category_pack" + ).id + + @api.depends("company_id", "community_company_mids") def _compute_allowed_community_company_ids(self): for record in self: - record.allowed_community_company_ids = self.env["res.company"].search( - [ - ("hierarchy_level", "=", "community"), - ("parent_id", "=", record.company_id.id), - ] - ) + query = [("hierarchy_level", "=", "community")] + if record.community_company_mids: + query.append(("parent_id", "=", self.user_current_company.id)) + else: + query.append(("parent_id", "=", record.company_id.id)) + record.allowed_community_company_ids = self.env["res.company"].search(query) + @api.depends("company_id", "community_company_mids") def _compute_allowed_payment_mode_ids(self): for record in self: + if record.community_company_mids: + query = [("company_id", "=", self.user_current_company.id)] + else: + query = [("company_id", "=", record.company_id.id)] record.allowed_payment_mode_ids = self.env["account.payment.mode"].search( - [("company_id", "=", self.user_current_company.id)] + query ) @api.onchange("company_id") - def _on_change_company_id(self): + def _compute_service_invoicing_action_create_wizard_allowed_values(self): for record in self: record._compute_allowed_community_company_ids() record._compute_allowed_payment_mode_ids() - # TODO: This should be necessary if pack_product_product_ids gets properly auto computed - record._compute_pack_product_product_ids() def execute_create(self): - # Check if already open one and raise error - existing_contract = get_existing_open_contract( - self.env, self.company_id.partner_id, self.community_company_id - ) - if existing_contract: - raise_existing_same_open_contract_error() + if self.community_company_mids: + for community in self.community_company_mids: + self._execute_create_one( + community, + community.parent_id, + self.env.company.service_invoicing_payment_mode_id, + ) + return service_invoicing_tree_view(self.env) + else: + service_invoicing_id = self._execute_create_one( + self.community_company_id, self.company_id, self.payment_mode_id + ) + return service_invoicing_form_view_for_platform_admins( + self.env, service_invoicing_id + ) + + def execute_create_one(self, community_company_id, company_id, payment_mode_id): + self._validate_service_invoicing_action_create([community_company_id.id]) existing_closed_contract = get_existing_last_closed_contract( - self.env, self.company_id.partner_id, self.community_company_id + self.env, company_id.partner_id, community_company_id ) # If existing closed contract reopen it if existing_closed_contract: @@ -95,20 +121,84 @@ class ServiceInvoicingActionCreateWizard(models.TransientModel): self.pricelist_id, self.service_pack_id, self.discount, - self.payment_mode_id, + payment_mode_id, ) # If none of previous create a new contract else: with sale_order_utils(self.env) as component: service_invoicing_id = component.create_service_invoicing_initial( - self.company_id, - self.community_company_id, + company_id, + community_company_id, self.service_pack_id, self.pricelist_id, - self.payment_mode_id, + payment_mode_id, datetime.now(), self.discount, "activate", "active_platform_service_invocing", ) - return service_invoicing_view(self.env, service_invoicing_id) + return service_invoicing_id + + def get_service_invoicing_action_create_wizard_form_view(self): + if "active_ids" in self.env.context.keys(): + self._validate_service_invoicing_action_create( + self.env.context["active_ids"] + ) + self._validate_service_invoicing_action_create_multicommunity( + self.env.context["active_ids"] + ) + wizard = self.env["service.invoicing.action.create.wizard"].create( + { + "community_company_mids": self.env.context["active_ids"], + } + ) + return { + "type": "ir.actions.act_window", + "res_model": "service.invoicing.action.create.wizard", + "views": [ + ( + self.env.ref( + "energy_communities_service_invoicing.view_service_invoicing_action_create_wizard_form" + ).id, + "form", + ), + ], + "target": "new", + "res_id": wizard.id, + } + return False + + def _validate_service_invoicing_action_create(self, company_id_list): + impacted_records = self.env["res.company"].browse(company_id_list) + # Check all selected companies are communities + hierarchy_levels = list(set(impacted_records.mapped("hierarchy_level"))) + if len(hierarchy_levels) > 1 or hierarchy_levels[0] != "community": + raise ValidationError(_("You can only assign pack to communities")) + # Check if already open one and raise error + for record in impacted_records: + existing_contract = get_existing_open_contract( + self.env, record.parent_id.partner_id, record + ) + if existing_contract: + raise_existing_same_open_contract_error(existing_contract) + + def _validate_service_invoicing_action_create_multicommunity(self, company_id_list): + impacted_records = self.env["res.company"].browse(company_id_list) + # check all communities have coordinator defined + for record in impacted_records: + if not record.parent_id: + raise ValidationError( + _("Community {} must have a parent coordinator defined").format( + record.name + ) + ) + # Check current company has configuration payment mode for multicompany creation + if ( + self.community_company_mids + and not self.env.company.service_invoicing_payment_mode_id + ): + raise ValidationError( + _( + "Platform {} must have a service invoicing payment mode defined" + ).format(self.env.company.name) + ) diff --git a/energy_communities_service_invoicing/wizards/service_invoicing_action_create.xml b/energy_communities_service_invoicing/wizards/service_invoicing_action_create.xml index 147f07487..776c34b6e 100644 --- a/energy_communities_service_invoicing/wizards/service_invoicing_action_create.xml +++ b/energy_communities_service_invoicing/wizards/service_invoicing_action_create.xml @@ -11,12 +11,26 @@ <group> <field name="allowed_community_company_ids" invisible="1" /> <field name="allowed_payment_mode_ids" invisible="1" /> - <field name="pack_product_product_ids" invisible="1" /> - <field name="company_id" required="1" domain="[('hierarchy_level','=','coordinator')]"/> - <field name="community_company_id" required="1" /> - <field name="service_pack_id" required="1"/> + <field name="pack_product_categ_id" invisible="1" /> + <field + name="company_id" + domain="[('hierarchy_level','=','coordinator')]" + attrs="{'invisible':[('community_company_mids','!=',[])],'required':[('community_company_mids','=',[])]}" + /> + <field + name="community_company_id" + attrs="{'invisible':[('community_company_mids','!=',[])],'required':[('community_company_mids','=',[])]}" + /> + <field name="community_company_mids" /> + <field name="service_pack_id" + required="1" + domain="[('categ_id','=',pack_product_categ_id)]" + /> <field name="pricelist_id" required="1" domain="[('company_id','=',False)]"/> - <field name="payment_mode_id" required="1" /> + <field + name="payment_mode_id" + attrs="{'invisible':[('community_company_mids','!=',[])],'required':[('community_company_mids','=',[])]}" + /> <field name="discount" required="1" /> </group> </sheet> -- GitLab