diff --git a/numigi_test_crm_louarmassi/README.rst b/numigi_test_crm_louarmassi/README.rst new file mode 100644 index 0000000..f7600bf --- /dev/null +++ b/numigi_test_crm_louarmassi/README.rst @@ -0,0 +1,49 @@ +Technical test ODOO - CRM +========================== +This module add custom features on CRM module + +.. contents:: Table of Contents + +Context +------- +Custom development on crm and website_crm modules, no configuration will be required after the installation of this module + +Overview +-------- +A new field is created on crm team form view containing all email addresses of the team members,separated by commas + + +.. image:: static/description/team_emails.png + +When the team manager is selected on the team form, it will be automatically added to the team members + + +.. image:: static/description/team_leader.png + +Three new teams will be created after the module installation + + +.. image:: static/description/teams.png + + +In the CRM configurator, these two fields will be enabled by default: leads, Incoming emails. + + +.. image:: static/description/crm_setting_default.png + + +A cron is created to send a notification to the associated members if an opportunity has not progressed beyond the draft stage for more than 10 days. + + +.. image:: static/description/notify_member_cron.png + + +On all views of leads and opportunities, the “Expected Revenue” field will be visible only to the Sales Administrator group. + +On the crm Contact Form from the website, the created lead is assigned to the default Team(Équipe de vente). + + +Contributors +------------ + +The `Numigi `_ team is the contributor to this project. \ No newline at end of file diff --git a/numigi_test_crm_louarmassi/__init__.py b/numigi_test_crm_louarmassi/__init__.py new file mode 100644 index 0000000..86dbe1c --- /dev/null +++ b/numigi_test_crm_louarmassi/__init__.py @@ -0,0 +1,13 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import models + +from odoo import api, fields, SUPERUSER_ID, _ + + +def crm_refresh_res_setting(cr, registry): + env = api.Environment(cr, SUPERUSER_ID, {}) + + # Recalculate computed fields of res.config.setting + env["res.config.settings"].search([]).write({}) diff --git a/numigi_test_crm_louarmassi/__manifest__.py b/numigi_test_crm_louarmassi/__manifest__.py new file mode 100644 index 0000000..0bcbd48 --- /dev/null +++ b/numigi_test_crm_louarmassi/__manifest__.py @@ -0,0 +1,23 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "Numigi crm test", + "version": "1.0.0", + "author": "Youness LOUARMASSI", + "maintainer": "Numigi", + "license": "LGPL-3", + "category": "Other", + "summary": "Custom development on CRM module", + "depends": ["crm", "website_crm"], + "data": [ + "security/crm_security.xml", + "data/crm_data.xml", + "data/mail_data.xml", + "data/service_cron.xml", + "views/crm_team_views.xml", + "views/crm_lead_views.xml", + ], + "installable": True, + "post_init_hook": "crm_refresh_res_setting", +} diff --git a/numigi_test_crm_louarmassi/data/crm_data.xml b/numigi_test_crm_louarmassi/data/crm_data.xml new file mode 100644 index 0000000..442f842 --- /dev/null +++ b/numigi_test_crm_louarmassi/data/crm_data.xml @@ -0,0 +1,29 @@ + + + + + Équipe Support Technique + + + + Équipe ventes + + + + + + Équipe SAV + partners + + + + + crm.generate_lead_from_alias + True + + + + + + + diff --git a/numigi_test_crm_louarmassi/data/mail_data.xml b/numigi_test_crm_louarmassi/data/mail_data.xml new file mode 100644 index 0000000..aa859b4 --- /dev/null +++ b/numigi_test_crm_louarmassi/data/mail_data.xml @@ -0,0 +1,25 @@ + + + + + + Notify team members + + ${object.company_id.name} | Suivi opportunité + ${(object.company_id.email or user.email) | safe} + ${object.team_id.emails | safe} + +
+

+ Bonjour,
+
+ Merci de donner une suite à cette opportunité ${object.name}.
+
+ Cordialement. +

+ +
+
+
+
+
diff --git a/numigi_test_crm_louarmassi/data/service_cron.xml b/numigi_test_crm_louarmassi/data/service_cron.xml new file mode 100644 index 0000000..deace5a --- /dev/null +++ b/numigi_test_crm_louarmassi/data/service_cron.xml @@ -0,0 +1,14 @@ + + + + + Notify crm team members + 1 + days + -1 + + + model._notify_members() + code + + diff --git a/numigi_test_crm_louarmassi/models/__init__.py b/numigi_test_crm_louarmassi/models/__init__.py new file mode 100644 index 0000000..46d7d2d --- /dev/null +++ b/numigi_test_crm_louarmassi/models/__init__.py @@ -0,0 +1,5 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import crm_team +from . import crm_lead diff --git a/numigi_test_crm_louarmassi/models/crm_lead.py b/numigi_test_crm_louarmassi/models/crm_lead.py new file mode 100644 index 0000000..2850f81 --- /dev/null +++ b/numigi_test_crm_louarmassi/models/crm_lead.py @@ -0,0 +1,40 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import api, fields, models, _ +from _datetime import timedelta +from werkzeug.urls import url_join + + +class Lead(models.Model): + _inherit = "crm.lead" + + expected_revenue = fields.Monetary(groups="sales_team.group_sale_manager") + + @api.model + def _notify_members(self): + template = self.env.ref( + "numigi_test_crm_louarmassi.email_template_notify_members", raise_if_not_found=False + ) + new_leads = self._get_draft_leads_10days() + for lead in new_leads: + template.send_mail(lead.id, force_send=True) + + @api.model + def _get_draft_leads_10days(self): + stage_new = self.env.ref("crm.stage_lead1") + date_before_10days = fields.Datetime.now() - timedelta(days=10) + lead_domain = [ + ("type", "=", "opportunity"), + ("stage_id", "=", stage_new.id), + ("date_last_stage_update", "<=", date_before_10days), + ("team_id", "!=", False), + ] + new_leads = self.search(lead_domain) + return new_leads + + def get_access_link(self): + self.ensure_one() + web_base_url = self.get_base_url() + access_link = url_join(web_base_url, f"/web#id={self.id}&model=crm.lead&view_type=form") + return access_link diff --git a/numigi_test_crm_louarmassi/models/crm_team.py b/numigi_test_crm_louarmassi/models/crm_team.py new file mode 100644 index 0000000..eb0b4fc --- /dev/null +++ b/numigi_test_crm_louarmassi/models/crm_team.py @@ -0,0 +1,21 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import api, fields, models, _ + + +class Team(models.Model): + _inherit = "crm.team" + + emails = fields.Char("Emails", compute="_compute_emails") + + @api.depends("member_ids.email") + def _compute_emails(self): + for team in self: + members_email = [member.email for member in team.member_ids if member.email] + team.emails = ",".join(members_email) + + @api.onchange("user_id") + def onchange_user_id(self): + if self.user_id: + self.member_ids = [(4, self.user_id.id)] diff --git a/numigi_test_crm_louarmassi/security/crm_security.xml b/numigi_test_crm_louarmassi/security/crm_security.xml new file mode 100644 index 0000000..64dd416 --- /dev/null +++ b/numigi_test_crm_louarmassi/security/crm_security.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/numigi_test_crm_louarmassi/static/description/crm_form.png b/numigi_test_crm_louarmassi/static/description/crm_form.png new file mode 100644 index 0000000..08db97d Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/crm_form.png differ diff --git a/numigi_test_crm_louarmassi/static/description/crm_form_sales_team.png b/numigi_test_crm_louarmassi/static/description/crm_form_sales_team.png new file mode 100644 index 0000000..87ac667 Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/crm_form_sales_team.png differ diff --git a/numigi_test_crm_louarmassi/static/description/crm_setting_default.png b/numigi_test_crm_louarmassi/static/description/crm_setting_default.png new file mode 100644 index 0000000..cb0d267 Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/crm_setting_default.png differ diff --git a/numigi_test_crm_louarmassi/static/description/icon.png b/numigi_test_crm_louarmassi/static/description/icon.png new file mode 100644 index 0000000..92a86b1 Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/icon.png differ diff --git a/numigi_test_crm_louarmassi/static/description/notify_member_cron.png b/numigi_test_crm_louarmassi/static/description/notify_member_cron.png new file mode 100644 index 0000000..e74e8df Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/notify_member_cron.png differ diff --git a/numigi_test_crm_louarmassi/static/description/notify_member_email.png b/numigi_test_crm_louarmassi/static/description/notify_member_email.png new file mode 100644 index 0000000..a2e481f Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/notify_member_email.png differ diff --git a/numigi_test_crm_louarmassi/static/description/team_emails.png b/numigi_test_crm_louarmassi/static/description/team_emails.png new file mode 100644 index 0000000..6a02461 Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/team_emails.png differ diff --git a/numigi_test_crm_louarmassi/static/description/team_leader.png b/numigi_test_crm_louarmassi/static/description/team_leader.png new file mode 100644 index 0000000..ec23d47 Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/team_leader.png differ diff --git a/numigi_test_crm_louarmassi/static/description/teams.png b/numigi_test_crm_louarmassi/static/description/teams.png new file mode 100644 index 0000000..f64c0fc Binary files /dev/null and b/numigi_test_crm_louarmassi/static/description/teams.png differ diff --git a/numigi_test_crm_louarmassi/tests/__init__.py b/numigi_test_crm_louarmassi/tests/__init__.py new file mode 100644 index 0000000..2cbd564 --- /dev/null +++ b/numigi_test_crm_louarmassi/tests/__init__.py @@ -0,0 +1,4 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import test_crm_team diff --git a/numigi_test_crm_louarmassi/tests/test_crm_team.py b/numigi_test_crm_louarmassi/tests/test_crm_team.py new file mode 100644 index 0000000..af2b01a --- /dev/null +++ b/numigi_test_crm_louarmassi/tests/test_crm_team.py @@ -0,0 +1,56 @@ +# © Numigi (tm) and all its contributors (https://numigi.com/r/home) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from datetime import date, timedelta +from odoo import fields +from odoo.tests.common import tagged, users +from odoo.tests.common import Form +from odoo.addons.crm.tests.common import TestCrmCommon + + +class TestCrmTeam(TestCrmCommon): + @classmethod + def setUpClass(cls): + super(TestCrmTeam, cls).setUpClass() + cls.opport_1 = cls.env["crm.lead"].create( + { + "name": "Nibbler Spacecraft Request", + "type": "opportunity", + "user_id": cls.user_sales_leads.id, + "team_id": cls.sales_team_1.id, + "partner_id": False, + "contact_name": "Amy Wong", + "email_from": "amy.wong@test.example.com", + "country_id": cls.env.ref("base.us").id, + "stage_id": cls.env.ref("crm.stage_lead1").id, + } + ) + + def test_crm_team_emails(self): + """Test Emails field containing all email addresses of team members, + separated by commas.""" + field_emails = self.sales_team_1.emails.split(",") + member_emails = [member.email for member in self.sales_team_1.member_ids if member.email] + self.assertEqual(field_emails, member_emails) + + def test_crm_team_manager(self): + """Test if a team manager is also a team member""" + team_form = Form(self.sales_team_1) + team_form.user_id = self.user_sales_manager + self.assertIn(team_form.user_id, team_form.member_ids) + + def test_draft_leads_10days(self): + self.opport_1.write( + { + "date_last_stage_update": fields.Datetime.now() - timedelta(days=11), + } + ) + draft_before_10days_leads = self.env["crm.lead"]._get_draft_leads_10days() + self.assertIn(self.opport_1, draft_before_10days_leads) + self.opport_1.write( + { + "date_last_stage_update": fields.Datetime.now() - timedelta(days=9), + } + ) + draft_before_10days_leads = self.env["crm.lead"]._get_draft_leads_10days() + self.assertNotIn(self.opport_1, draft_before_10days_leads) diff --git a/numigi_test_crm_louarmassi/views/crm_lead_views.xml b/numigi_test_crm_louarmassi/views/crm_lead_views.xml new file mode 100644 index 0000000..6058de1 --- /dev/null +++ b/numigi_test_crm_louarmassi/views/crm_lead_views.xml @@ -0,0 +1,25 @@ + + + + crm.lead.form.numigi + crm.lead + + + + sales_team.group_sale_manager + + + + + + crm.lead.kanban.lead.numigi + crm.lead + + + + + sales_team.group_sale_manager + + + + diff --git a/numigi_test_crm_louarmassi/views/crm_team_views.xml b/numigi_test_crm_louarmassi/views/crm_team_views.xml new file mode 100644 index 0000000..dee0745 --- /dev/null +++ b/numigi_test_crm_louarmassi/views/crm_team_views.xml @@ -0,0 +1,17 @@ + + + + + crm.team.form.inherit.test + crm.team + + 20 + + + + + + + + +