From c651ac4355cf978de3adaf9ad57d7204c4fcc66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phan=20Sainl=C3=A9ger?= Date: Sun, 16 Oct 2022 18:02:33 +0200 Subject: [PATCH] [ADD] partner_profiles: create add-on --- partner_profiles/.gitignore | 2 + partner_profiles/README.rst | 43 +++ partner_profiles/__init__.py | 3 + partner_profiles/__manifest__.py | 43 +++ .../data/partner_profile_data.xml | 19 + partner_profiles/data/res_partner_data.xml | 29 ++ partner_profiles/i18n/README | 1 + partner_profiles/i18n/fr.po | 173 +++++++++ partner_profiles/i18n/partner_profiles.pot | 173 +++++++++ partner_profiles/models/__init__.py | 5 + partner_profiles/models/partner_profile.py | 14 + partner_profiles/models/res_partner.py | 330 ++++++++++++++++++ partner_profiles/security/ir.model.access.csv | 3 + .../views/calendar_event_view.xml | 16 + .../views/partner_profile_view.xml | 22 ++ partner_profiles/views/res_partner_view.xml | 71 ++++ 16 files changed, 947 insertions(+) create mode 100644 partner_profiles/.gitignore create mode 100644 partner_profiles/README.rst create mode 100644 partner_profiles/__init__.py create mode 100644 partner_profiles/__manifest__.py create mode 100644 partner_profiles/data/partner_profile_data.xml create mode 100644 partner_profiles/data/res_partner_data.xml create mode 100644 partner_profiles/i18n/README create mode 100644 partner_profiles/i18n/fr.po create mode 100644 partner_profiles/i18n/partner_profiles.pot create mode 100644 partner_profiles/models/__init__.py create mode 100644 partner_profiles/models/partner_profile.py create mode 100644 partner_profiles/models/res_partner.py create mode 100644 partner_profiles/security/ir.model.access.csv create mode 100644 partner_profiles/views/calendar_event_view.xml create mode 100644 partner_profiles/views/partner_profile_view.xml create mode 100644 partner_profiles/views/res_partner_view.xml diff --git a/partner_profiles/.gitignore b/partner_profiles/.gitignore new file mode 100644 index 0000000..6da5887 --- /dev/null +++ b/partner_profiles/.gitignore @@ -0,0 +1,2 @@ +*.*~ +*pyc diff --git a/partner_profiles/README.rst b/partner_profiles/README.rst new file mode 100644 index 0000000..314776d --- /dev/null +++ b/partner_profiles/README.rst @@ -0,0 +1,43 @@ +================ +partner_profiles +================ + +Provide several profiles for one person. + +Installation +============ + +Use Odoo normal module installation procedure to install +``partner_profiles``. + +Known issues / Roadmap +====================== + +None yet. +Bug Tracker +=========== + +Bugs are tracked on `our issues website `_. In case of +trouble, please check there if your issue has already been +reported. If you spotted it first, help us smashing it by providing a +detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Stéphan Sainléger + +Funders +------- + +The development of this module has been financially supported by: +* Elabore (https://elabore.coop) + + +Maintainer +---------- + +This module is maintained by Elabore. \ No newline at end of file diff --git a/partner_profiles/__init__.py b/partner_profiles/__init__.py new file mode 100644 index 0000000..5305644 --- /dev/null +++ b/partner_profiles/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/partner_profiles/__manifest__.py b/partner_profiles/__manifest__.py new file mode 100644 index 0000000..436bce0 --- /dev/null +++ b/partner_profiles/__manifest__.py @@ -0,0 +1,43 @@ +# Copyright 2022 Stéphan Sainléger (Elabore) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "partner_profiles", + "version": "12.0.1.0.0", + "author": "Elabore", + "website": "https://elabore.coop", + "maintainer": "Stéphan Sainléger", + "license": "AGPL-3", + "category": "Tools", + "summary": "Provide several profiles for one person.", + # any module necessary for this one to work correctly + "depends": [ + "base", + "calendar", + "partner_contact_in_several_companies", + ], + "qweb": [ + # "static/src/xml/*.xml", + ], + "external_dependencies": { + "python": [], + }, + # always loaded + "data": [ + "security/ir.model.access.csv", + "views/res_partner_view.xml", + "views/calendar_event_view.xml", + "views/partner_profile_view.xml", + "data/partner_profile_data.xml", + "data/res_partner_data.xml", + ], + # only loaded in demonstration mode + "demo": [], + "js": [], + "css": [], + "installable": True, + # Install this module automatically if all dependency have been previously + # and independently installed. Used for synergetic or glue modules. + "auto_install": False, + "application": False, +} \ No newline at end of file diff --git a/partner_profiles/data/partner_profile_data.xml b/partner_profiles/data/partner_profile_data.xml new file mode 100644 index 0000000..941f72a --- /dev/null +++ b/partner_profiles/data/partner_profile_data.xml @@ -0,0 +1,19 @@ + + + + + Main Profile + partner_profile_main + + + + Public Profile + partner_profile_public + + + + Position Profile + partner_profile_position + + + \ No newline at end of file diff --git a/partner_profiles/data/res_partner_data.xml b/partner_profiles/data/res_partner_data.xml new file mode 100644 index 0000000..322c8f7 --- /dev/null +++ b/partner_profiles/data/res_partner_data.xml @@ -0,0 +1,29 @@ + + + + + Partner: generate missing public profiles + + code + model._cron_generate_missing_public_profiles() + days + -1 + 0 + + + + Partner: Migration Standard Partners to Partners with Profiles + + code + +model._migration_create_pro_profiles(limit=200) +model._migration_person_without_parent(limit=200) +model._migration_person_with_parent_and_existing_main(limit=200) +model._migration_person_with_parent_not_existing_main(limit=200) + + days + -1 + 0 + + + \ No newline at end of file diff --git a/partner_profiles/i18n/README b/partner_profiles/i18n/README new file mode 100644 index 0000000..62197a1 --- /dev/null +++ b/partner_profiles/i18n/README @@ -0,0 +1 @@ +This directory should contain the *.po for Odoo translation. diff --git a/partner_profiles/i18n/fr.po b/partner_profiles/i18n/fr.po new file mode 100644 index 0000000..2bd482e --- /dev/null +++ b/partner_profiles/i18n/fr.po @@ -0,0 +1,173 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_profiles +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-11-09 14:54+0000\n" +"PO-Revision-Date: 2022-11-09 14:54+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: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Administrative Name" +msgstr "Nom Administratif" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Company" +msgstr "Société" + +#. module: partner_profiles +#: model:ir.model,name:partner_profiles.model_res_partner +msgid "Contact" +msgstr "" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Create Public Profile" +msgstr "Créer le profil public" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__has_position +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__has_position +msgid "Has Position" +msgstr "A une position" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__id +msgid "ID" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_main_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_main_profile +msgid "Is Main Profile" +msgstr "Est un profil Principal" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_position_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_position_profile +msgid "Is Position Profile" +msgstr "Est un profil Position" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_public_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_public_profile +msgid "Is Public Profile" +msgstr "Est un profil Public" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +#: model:partner.profile,name:partner_profiles.partner_profile_main +msgid "Main Profile" +msgstr "Profil principal" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__name +msgid "Name" +msgstr "Nom" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__other_contact_ids +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__other_contact_ids +msgid "Others Positions" +msgstr "Autres fonctions" + +#. module: partner_profiles +#: model:ir.actions.act_window,name:partner_profiles.partner_profile_action +msgid "Partner Profiles" +msgstr "Profiles de contact" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__partner_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__partner_profile +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Partner profile" +msgstr "Profil de contact" + +#. module: partner_profiles +#: model:ir.model,name:partner_profiles.model_partner_profile +msgid "Partner profile to differentiate the attached partner entries" +msgstr "Profil de contact pour différentier les champs du contact" + +#. module: partner_profiles +#: model:ir.ui.menu,name:partner_profiles.menu_partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profile_view_tree +msgid "Partner profiles" +msgstr "Profiles de contact" + +#. module: partner_profiles +#: model:ir.actions.server,name:partner_profiles.ir_cron_migration_partner_profiles_ir_actions_server +#: model:ir.cron,cron_name:partner_profiles.ir_cron_migration_partner_profiles +#: model:ir.cron,name:partner_profiles.ir_cron_migration_partner_profiles +msgid "Partner: Migration Standard Partners to Partners with Profiles" +msgstr "Contact : Migration des Contacts standards aux Conctacts à profile" + +#. module: partner_profiles +#: model:ir.actions.server,name:partner_profiles.ir_cron_generate_missing_public_profiles_ir_actions_server +#: model:ir.cron,cron_name:partner_profiles.ir_cron_generate_missing_public_profiles +#: model:ir.cron,name:partner_profiles.ir_cron_generate_missing_public_profiles +msgid "Partner: generate missing public profiles" +msgstr "Contact : Générer les profil publics manquant" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +#: model:partner.profile,name:partner_profiles.partner_profile_position +msgid "Position Profile" +msgstr "Profil position" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +#: model:partner.profile,name:partner_profiles.partner_profile_public +msgid "Public Profile" +msgstr "Profil public" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__public_profile_id +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__public_profile_id +msgid "Public profile" +msgstr "Profil public" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__ref +msgid "Ref" +msgstr "" + diff --git a/partner_profiles/i18n/partner_profiles.pot b/partner_profiles/i18n/partner_profiles.pot new file mode 100644 index 0000000..19aa655 --- /dev/null +++ b/partner_profiles/i18n/partner_profiles.pot @@ -0,0 +1,173 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_profiles +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-11-09 14:53+0000\n" +"PO-Revision-Date: 2022-11-09 14: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: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Administrative Name" +msgstr "" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Company" +msgstr "" + +#. module: partner_profiles +#: model:ir.model,name:partner_profiles.model_res_partner +msgid "Contact" +msgstr "" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Create Public Profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_uid +msgid "Created by" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__create_date +msgid "Created on" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__display_name +msgid "Display Name" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__has_position +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__has_position +msgid "Has Position" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__id +msgid "ID" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_main_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_main_profile +msgid "Is Main Profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_position_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_position_profile +msgid "Is Position Profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__is_public_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__is_public_profile +msgid "Is Public Profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile____last_update +msgid "Last Modified on" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__write_date +msgid "Last Updated on" +msgstr "" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +#: model:partner.profile,name:partner_profiles.partner_profile_main +msgid "Main Profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__name +msgid "Name" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__other_contact_ids +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__other_contact_ids +msgid "Others Positions" +msgstr "" + +#. module: partner_profiles +#: model:ir.actions.act_window,name:partner_profiles.partner_profile_action +msgid "Partner Profiles" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__partner_profile +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__partner_profile +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +msgid "Partner profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model,name:partner_profiles.model_partner_profile +msgid "Partner profile to differentiate the attached partner entries" +msgstr "" + +#. module: partner_profiles +#: model:ir.ui.menu,name:partner_profiles.menu_partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profile_view_tree +msgid "Partner profiles" +msgstr "" + +#. module: partner_profiles +#: model:ir.actions.server,name:partner_profiles.ir_cron_migration_partner_profiles_ir_actions_server +#: model:ir.cron,cron_name:partner_profiles.ir_cron_migration_partner_profiles +#: model:ir.cron,name:partner_profiles.ir_cron_migration_partner_profiles +msgid "Partner: Migration Standard Partners to Partners with Profiles" +msgstr "" + +#. module: partner_profiles +#: model:ir.actions.server,name:partner_profiles.ir_cron_generate_missing_public_profiles_ir_actions_server +#: model:ir.cron,cron_name:partner_profiles.ir_cron_generate_missing_public_profiles +#: model:ir.cron,name:partner_profiles.ir_cron_generate_missing_public_profiles +msgid "Partner: generate missing public profiles" +msgstr "" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +#: model:partner.profile,name:partner_profiles.partner_profile_position +msgid "Position Profile" +msgstr "" + +#. module: partner_profiles +#: model_terms:ir.ui.view,arch_db:partner_profiles.partner_profiles_form_view +#: model:partner.profile,name:partner_profiles.partner_profile_public +msgid "Public Profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_res_partner__public_profile_id +#: model:ir.model.fields,field_description:partner_profiles.field_res_users__public_profile_id +msgid "Public profile" +msgstr "" + +#. module: partner_profiles +#: model:ir.model.fields,field_description:partner_profiles.field_partner_profile__ref +msgid "Ref" +msgstr "" + diff --git a/partner_profiles/models/__init__.py b/partner_profiles/models/__init__.py new file mode 100644 index 0000000..f3f09aa --- /dev/null +++ b/partner_profiles/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2020 Elabore (https://elabore.coop) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import partner_profile +from . import res_partner diff --git a/partner_profiles/models/partner_profile.py b/partner_profiles/models/partner_profile.py new file mode 100644 index 0000000..292d68d --- /dev/null +++ b/partner_profiles/models/partner_profile.py @@ -0,0 +1,14 @@ +# Copyright 2022 Elabore (https://elabore.coop) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models, fields + + +class PartnerProfile(models.Model): + _name = "partner.profile" + _description = "Partner profile to differentiate the attached partner entries" + + name = fields.Char(string="Name", required=True, translate=True, readonly=False) + ref = fields.Char(string="Ref", required=True, translate=False, readonly=False) + + # TODO: block unlink method. diff --git a/partner_profiles/models/res_partner.py b/partner_profiles/models/res_partner.py new file mode 100644 index 0000000..fb9d297 --- /dev/null +++ b/partner_profiles/models/res_partner.py @@ -0,0 +1,330 @@ +# Copyright 2022 Elabore (https://elabore.coop) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging +from odoo import _, api, fields, models + +_logger = logging.getLogger(__name__) + + +class res_partner(models.Model): + _inherit = "res.partner" + + partner_profile = fields.Many2one( + "partner.profile", + string="Partner profile", + required=False, + translate=False, + readonly=False, + ) + is_main_profile = fields.Boolean(compute="_compute_profile_booleans", store=True) + is_public_profile = fields.Boolean(compute="_compute_profile_booleans", store=True) + is_position_profile = fields.Boolean( + compute="_compute_profile_booleans", store=True + ) + has_position = fields.Boolean(compute="_compute_profile_booleans", store=True) + + # If current partner is Main partner, this field indicates what its public profile is. + public_profile_id = fields.Many2one( + "res.partner", + compute="_compute_public_profile_id", + string="Public profile", + store=True, + ondelete="cascade", + ) + + # If current partner is Main partner, this field indicates what its position profiles are. + other_contact_ids = fields.One2many( + domain=[("is_position_profile", "=", True)] + ) + + @api.depends("partner_profile", "other_contact_ids") + def _compute_profile_booleans(self): + for partner in self: + partner.is_main_profile = ( + partner.partner_profile.ref == "partner_profile_main" + ) + partner.is_public_profile = ( + partner.partner_profile.ref == "partner_profile_public" + ) + partner.is_position_profile = ( + partner.partner_profile.ref == "partner_profile_position" + ) + partner.has_position = len(partner.other_contact_ids) > 0 + + @api.depends("partner_profile", "contact_id") + def _compute_public_profile_id(self): + for partner in self: + if partner.is_main_profile: + partner.public_profile_id = self.env["res.partner"].search( + [ + ("contact_id", "=", partner.id), + ("is_public_profile", "=", True), + ], + limit=1, + ) + + @api.onchange("type") + def _onchange_type(self): + self.contact_type = "standalone" + self.partner_profile = False + if self.type == "contact" and self.parent_id: + _logger.debug("Contact type: attached") + # A contact with parent_id is partner_profile=Position, and contact_type=attached + position_profile = self.env.ref("partner_profiles.partner_profile_position") + self.contact_type = "attached" + self.partner_profile = position_profile.id + + @api.model + def create(self, vals): + """Assume if not type, default is contact""" + vals["type"] = vals.get("type", "contact") + if vals["type"] == "contact": + """When creating, if partner_profile is not defined by a previous process, the defaut value is Main""" + modified_self = self._basecontact_check_context("create") + if not vals.get("partner_profile") and not vals.get("contact_id"): + profile = self.env.ref("partner_profiles.partner_profile_main").read()[0] + vals["partner_profile"] = profile["id"] + res = super(res_partner, modified_self).create(vals) + # Creation of the public profile + if ( + res.partner_profile.ref == "partner_profile_main" #TODO: replace by check on boolean is_main_profile ? Is this boolean computed at this step of the process? + and not res.public_profile_id + ): + res.create_public_profile() + if res.partner_profile.ref == "partner_profile_public": #TODO: replace by check on boolean is_public_profile ? Is this boolean computed at this step of the process? + # Public profile can't be customer or supplier. Only main or position profiles can + res.customer = False + res.supplier = False + else: + modified_self = self._basecontact_check_context("create") + res = super(res_partner, modified_self).create(vals) + return res + + @api.model + def search_position_partners(self, profile): + if profile: + position_partners = self.env["res.partner"].search( + [("contact_id", "=", self.id), ("partner_profile", "=", profile)] + ) + else: + position_partners = self.env["res.partner"].search( + [("contact_id", "=", self.id)] + ) + return position_partners + + def _get_field_value(self, fname): + field = self._fields[fname] + if field.type == "many2one": + return self[fname].id + elif field.type == "one2many": + return None + elif field.type == "many2many": + return [(6, 0, self[fname].ids)] + else: + return self[fname] + + def _get_public_profile_fields(self): + fields = [ + "name", + "function", + "phone", + "mobile", + "email", + "street", + "street2", + "city", + "country_id", + "zip", + "is_company", + "lang", + ] + # Return the fields to copy in the public profile when it is created. + return fields + + @api.multi + def create_public_profile(self): + profile = self.env.ref("partner_profiles.partner_profile_public") + for partner in self: + _logger.debug("Create public profile [%s] %s" % (partner.id, partner.name)) + # Check if a public partner already exists + partner._compute_public_profile_id() + if not partner.public_profile_id: + values = { + "type": "other", + "contact_id": partner.id, + "partner_profile": profile.id, + "company_id": partner.company_id.id, + } + public_fields = partner._get_public_profile_fields() + for field_name in public_fields: + values[field_name] = partner._get_field_value(field_name) + partner.create(values) + partner._compute_public_profile_id() + + ################################################################################## + ## Planned actions + ################################################################################## + + @api.model + def _cron_generate_missing_public_profiles(self): + partners = self.search( + [("is_main_profile", "=", True), ("public_profile_id", "=", False)] + ) + for partner in partners: + partner.create_public_profile() + + def _get_concerned_partners_search_values( + self, + id=False, + is_company=False, + active=True, + with_parent=False, + ): + search_values = [ + ("is_company", "=", is_company), + ("active", "=", active), + ("partner_profile", "=", False) + ] + if id: + search_values.append(("id", "=", id)) + if with_parent and not is_company: + search_values.append(("parent_id", "!=", False)) + elif not is_company: + search_values.append(("parent_id", "=", False)) + return search_values + + @api.model + def _migration_create_pro_profiles(self, limit=None, id=False): + partner_profile_main = self.env.ref("partner_profiles.partner_profile_main") + + # Company migration + search_values = self._get_concerned_partners_search_values( + id, + is_company=True, + ) + partners = self.env["res.partner"].search(search_values, limit=limit) + _logger.debug("Company migration count: %s" % len(partners)) + if partners: + partners.write( + { + "partner_profile": partner_profile_main.id, + } + ) + partners.create_public_profile() + _logger.debug("### End migration ###") + + @api.model + def _migration_person_without_parent(self, limit=None, id=False): + partner_profile_main = self.env.ref("partner_profiles.partner_profile_main") + + # Person migration without parent_id + search_values = self._get_concerned_partners_search_values(id) + partners = self.env["res.partner"].search(search_values, limit=limit) + _logger.debug("Person without parent migration count: %s" % len(partners)) + if partners: + partners.write( + { + "partner_profile": partner_profile_main.id, + } + ) + _logger.debug("Create public profiles") + partners.create_public_profile() + _logger.debug("### End migration ###") + + def _get_main_partner_search_values(self, partner): + return [ + ("active", "=", True), + ("is_main_profile", "=", True), + ("is_company", "=", False), + "|", + ("name", "=", partner.name), + "&", + ("email", "!=", False), + ("email", "=", partner.email), + ] + + @api.model + def _migration_person_with_parent_and_existing_main( + self, limit=None, id=False + ): + partner_profile_position = self.env.ref("partner_profiles.partner_profile_position") + + # Person migration with parent_id + search_values = self._get_concerned_partners_search_values( + id, + with_parent=True, + ) + partners = self.env["res.partner"].search(search_values, limit=limit) + _logger.debug("Person migration with parent_id - migration count: %s" % len(partners)) + count = 0 + for partner in partners: + _logger.debug("count: [%s] : %s" % (count, partner.name)) + existing_main_partner = self.env["res.partner"].search( + self._get_main_partner_search_values(partner), + limit=1, + ) + if existing_main_partner: + _logger.debug("UPDATE Position") + partner.write( + { + "contact_id": existing_main_partner.id, + "partner_profile": partner_profile_position.id, + } + ) + count += 1 + _logger.debug("### End migration ###") + + def _get_create_main_partner_values(self, partner): + partner_profile_main = self.env.ref("partner_profiles.partner_profile_main") + return { + "partner_profile": partner_profile_main.id, + "company_id": partner.company_id.id, + "parent_id": False, + "name": partner.name, + } + + @api.model + def _migration_person_with_parent_not_existing_main( + self, limit=None, id=False + ): + + partners = self.env["res.partner"] + partner_profile_position = self.env.ref("partner_profiles.partner_profile_position") + + # Person migration with parent_id + search_values = self._get_concerned_partners_search_values( + id, + with_parent=True, + ) + partners = self.env["res.partner"].search(search_values, limit=limit) + _logger.debug("Person migration with parent_id - migration count: %s" % len(partners)) + count = 0 + for partner in partners: + _logger.debug("count: [%s] : %s" % (count, partner.name)) + existing_main_partner = self.env["res.partner"].search( + self._get_main_partner_search_values(partner), + limit=1, + ) + if not existing_main_partner: + default_values = self._get_create_main_partner_values(partner) + try: + main_partner = partner.copy(default=default_values) + except Exception as e: + _logger.debug("Email exist ! try with empty email") + default_values["email"] = "" + main_partner = partner.copy(default=default_values) + + _logger.debug( + "count: [%s] %s -> [%s] %s " + % (partner.id, partner.name, main_partner.id, main_partner.name) + ) + partner.write( + { + "partner_profile": partner_profile_position.id, + "contact_id": main_partner.id, + "type": "other", + } + ) + count += 1 + _logger.debug("Last clean") \ No newline at end of file diff --git a/partner_profiles/security/ir.model.access.csv b/partner_profiles/security/ir.model.access.csv new file mode 100644 index 0000000..2c0d115 --- /dev/null +++ b/partner_profiles/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_partner_profile_public,partner_profile_public,model_partner_profile,,1,0,0,0 +access_partner_profile_admin,partner_profile_admin,model_partner_profile,base.group_partner_manager,1,1,1,1 \ No newline at end of file diff --git a/partner_profiles/views/calendar_event_view.xml b/partner_profiles/views/calendar_event_view.xml new file mode 100644 index 0000000..9d07631 --- /dev/null +++ b/partner_profiles/views/calendar_event_view.xml @@ -0,0 +1,16 @@ + + + + + partner.profiles.calendar.event.view + calendar.event + + 99 + + + [('is_public_profile', '=', False)] + + + + + \ No newline at end of file diff --git a/partner_profiles/views/partner_profile_view.xml b/partner_profiles/views/partner_profile_view.xml new file mode 100644 index 0000000..e064dab --- /dev/null +++ b/partner_profiles/views/partner_profile_view.xml @@ -0,0 +1,22 @@ + + + + + partner.profile.view.tree + partner.profile + + + + + + + + + + Partner Profiles + partner.profile + tree + + + + \ No newline at end of file diff --git a/partner_profiles/views/res_partner_view.xml b/partner_profiles/views/res_partner_view.xml new file mode 100644 index 0000000..f9e958f --- /dev/null +++ b/partner_profiles/views/res_partner_view.xml @@ -0,0 +1,71 @@ + + + + + Partner Profiles Form View + res.partner + + 99 + + + + + + +

Main Profile

+

Public Profile

+

Position Profile

+
+ + + + + + + + + + + + + + + + + + + + {'invisible': [('is_company','=', False)]} + + + 1 + + + + + + + + + {'invisible': ['|', ('contact_id','!=',False), ('is_company','=',True)]} + + + true + + + {'default_partner_profile': 3, 'default_contact_id': active_id, 'default_name': name, 'default_street': street, 'default_street2': street2, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_supplier': supplier} + + + + + + +
+
+
+
\ No newline at end of file