bemade_partner_email_domain final

This commit is contained in:
Benoît Vézina 2023-11-07 08:20:42 -05:00
parent f5976d89ea
commit 13381f9ffa
8 changed files with 237 additions and 76 deletions

View file

@ -1,18 +1,34 @@
{
'name': 'Partner Email Domain Auto-Set',
'name': 'Automated Partner Association by Email Domain',
'version': '15.0.0.0.0',
'category': 'Extra Tools',
'summary': 'Allow to autolink partner based on email domain',
'summary': 'Automatically associates partners with companies using matching email domains',
'description': """
This module allows users to automatically link a partner to a company based on the email domain.
This advanced utility module empowers Odoo users with the capacity to automate partner-company associations
based directly on email domains. It helps in eliminating manual effort by establishing a rule of correlation
between the email domain of a partner and the corresponding division or a company.
The automation proceeds as follows:
- On creation of partner records, the system will cross-verify the email domain against the companies
in the records.
- If a match is detected, the partner will automatically be linked with that company.
This module also takes care of instances where there are multiple companies with the same email domain.
In such cases, an email is dispatched to the partner with a selection interface to finalize the association.
The module is a significant productivity enhancer for businesses that deal with a high number of partners
and require efficient management.
""",
'depends': [
'base',
'mail'
'mail',
'website'
],
'data': [
'views/res_partner_views.xml',
'data/mail_template.xml'
'data/mail_template_data.xml',
'data/template_data'
],
'license': 'AGPL-3',
'author': 'Bemade',

View file

@ -1,14 +1,40 @@
from odoo import http
from odoo.http import request
# Import necessary libraries
from odoo import http, _
#from odoo.http import request
# Define a controller class that inherits from http.Controller
class DivisionCompanyController(http.Controller):
@http.route('/select_division_company', type='http', auth='public', methods=['GET'])
# Decorator to set the routing rules for the method 'select_division_company'.
# The URL for this method will be '/select_division_company'
# It has public access and should be used for HTTP requests of type GET.
@http.route('/select_division_company', website=True, type='http', auth='public')
def select_division_company(self, partner_id, access_token, division_id, **kwargs):
partner = request.env['res.partner'].sudo().search([
('id', '=', int(partner_id)),
('access_token', '=', access_token)
# Search the 'res.partner' model for a record with the given partner_id using Super User access rights
partner = http.request.env['res.partner'].sudo().search([
('id', '=', int(partner_id))
])
# Check if a partner was found with the given ID
if not partner:
return request.render('website.404')
# If no partner found, render an error page with a translatable error message
return http.request.render('bemade_partner_email_domain.error_page',
{'error_message': _('The requested partner is not found.')})
else:
# If the partner exists and the access token matches, proceed with updating the partner's division
if access_token and access_token == partner.access_token:
# Update the partner's parent with the division_id
partner.write({'parent_id': int(division_id)})
# Set a confirmation message signaling that the partner has been associated with the division
confirmation_message = _('Partner %s is associated with the division %s.' % (partner.name, division_id))
# Render the error page (which in this case acts as a status page) with the confirmation message.
return http.request.render('bemade_partner_email_domain.error_page',
{'confirmation_message': confirmation_message})
else:
# If the access token was not provided or does not match, render an error page with an error message
return http.request.render('bemade_partner_email_domain.error_page',
{'error_message': _('No Access Token found or not matching for this partner.')})

View file

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<record id="email_template_division_selection" model="mail.template">
<field name="name">Division Selection: Choose Your Division</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="email_from">{{object.company_id.email_formatted or user.email_formatted}}</field>
<field name="partner_to">{{object.id}}</field>
<field name="subject">Select Your Division at {{object.company_id.name}}</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px">
<p style="margin: 0px; padding: 0px; font-size: 13px;">
Hello <t t-out="object.name or ''">Brandon Freeman</t>,
</p>
<p style="margin: 0px; padding: 0px; font-size: 13px;">
We noticed that you have registered with our company. To provide you with the best possible service, we need you to confirm the division of our company that you are working with.
</p>
<p style="margin: 0px; padding: 0px; font-size: 13px;">
Please click on the link below to select your division:
</p>
<p style="margin: 16px; padding: 0px; font-size: 13px;">
<a href="{{object.get_division_selection_url()}}" style="text-decoration: none; color: #875A7B;">Choose Your Division</a>
</p>
<p style="margin: 0px; padding: 0px; font-size: 13px;">
If you have any questions or did not register with us, please disregard this email or contact us directly.
</p>
<p style="margin: 0px; padding: 0px; font-size: 13px;">
<br/>Best regards,
</p>
<p style="margin: 0px; padding: 0px; font-size: 13px;">
<br/>The <t t-out="object.company_id.name"/> team.<br/>
<t t-esc="object.company_id.email"/><br/>
<t t-esc="object.company_id.phone"/>
</p>
</div>
</field>
<field name="lang">{{ object.lang }}</field>
<field name="auto_delete" eval="True"/>
</record>
</data>
</odoo>

View file

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<record id="email_template_select_parent" model="mail.template">
<field name="name">Division Selection: Choose Your Division</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="email_from">{{object.company_id.email_formatted or user.email_formatted}}</field>
<field name="partner_to">{{object.id}}</field>
<field name="subject">Select Your Division at {{object.company_id.name}}</field>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0"
style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial, sans-serif; color: #454748; width: 100%; border-collapse:separate;">
<tbody>
<tr>
<td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
<tbody>
<!-- HEADER -->
<tr>
<td align="center" style="min-width: 590px;">
<!-- Content here -->
</td>
</tr>
<!-- CONTENT -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tbody>
<tr>
<td valign="top" style="font-size: 13px;">
<p>Hello <t t-out="object.name or ''">Brandon Freeman</t>,</p>
<p>We noticed that you have registered with our company by sending an email or using our website. To provide you with the best possible service, we need you to confirm the division of your company that you are working for.</p>
<p>Please click on the link below to select your division:</p>
<ul>
<t t-foreach="ctx.get('links', {}).items()" t-as="company_name">
<li>
<a t-attf-href="{{ company_name[1] }}" style="font-size:12px">
<t t-esc="company_name[0]"/>
</a>
</li>
</t>
</ul>
<p>If you have any questions or did not register with us, please disregard this email or contact us directly.</p>
<p>Best regards,</p>
<p>The Durpro team.</p>
</td>
</tr>
<!-- More content can be added here -->
</tbody>
</table>
</td>
</tr>
<!-- FOOTER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590"
style="min-width: 590px; background-color: white; font-size: 11px; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tbody>
<tr>
<td valign="middle" align="left">
<t t-out="object.company_id.name or ''"/>
</td>
</tr>
<tr>
<td valign="middle" align="left" style="opacity: 0.7;">
<t t-out="object.company_id.phone or ''"/>
<t t-if="object.company_id.email">
| <a t-att-href="'mailto:%s' % object.company_id.email" style="text-decoration:none; color: #454748;" t-out="object.company_id.email or ''"></a>
</t>
<t t-if="object.company_id.website">
| <a t-att-href="'%s' % object.company_id.website" style="text-decoration:none; color: #454748;" t-out="object.company_id.website or ''"></a>
</t>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<!-- POWERED BY -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;">
<tbody>
<tr>
<td style="text-align: center; font-size: 13px;">
Powered by <a target="_blank" href="https://www.odoo.com?utm_source=db&amp;utm_medium=auth" style="color: #875A7B;">Odoo</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</field>
<field name="lang">{{ object.lang }}</field>
<field name="auto_delete" eval="True"/>
</record>
</data>
</odoo>

View file

@ -0,0 +1,17 @@
<odoo>
<data>
<template id="error_page">
<base href="/" />
<t t-call="website.layout">
<div id="wrap">
<t t-if="error_message">
<div class="alert alert-danger"><t t-esc="error_message"/></div>
</t>
<t t-if="confirmation_message">
<div class="alert alert-success"><t t-esc="confirmation_message"/></div>
</t>
</div>
</t>
</template>
</data>
</odoo>

View file

@ -0,0 +1,41 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * bemade_partner_email_domain
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: it@bemade.org\n"
"Last-Translator: chatgpt\n"
"Language-Team: French (http://www.transifex.com/odoo/odoo-14-0/language/fr_CA/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#: model:ir.model.fields,field_description:bemade_partner_email_domain.field_res_partner_access_token
msgid "Access Token"
msgstr "Jeton d'accès"
#: model:ir.model.fields,field_description:bemade_partner_email_domain.field_res_partner_email_domain
msgid "Email Domain"
msgstr "Domaine de courriel"
#: model:ir.model.fields,field_description:bemade_partner_email_domain.field_res_partner_is_subdivision
msgid "Subdivision"
msgstr "Subdivision"
#: code:addons/bemade_partner_email_domain/controllers/main.py:0
#, python-format
msgid "The requested partner is not found."
msgstr "Le partenaire demandé n'est pas trouvé."
#: code:addons/bemade_partner_email_domain/controllers/main.py:0
#, python-format
msgid "No Access Token found or not matching for this partner."
msgstr "Aucun jeton d'accès trouvé ou ne correspondant pas à ce partenaire."
#: code:addons/bemade_partner_email_domain/controllers/main.py:0
#, python-format
msgid "Partner %s is associated with the division %s."
msgstr "Le partenaire %s est associé à la division %s."

View file

@ -1,4 +1,5 @@
from odoo import api, fields, models, Command
import uuid
from odoo.addons.website.controllers.main import Website
@ -6,7 +7,6 @@ from odoo.addons.website.controllers.main import Website
class Partner(models.Model):
_inherit = 'res.partner'
domain_identifier = fields.Boolean(string='Domain identifier', default=False)
email_domain = fields.Char(string='Email Domain')
is_subdivision = fields.Boolean(string='Subdivision', default=False)
access_token = fields.Char(string='Access Token')
@ -14,23 +14,25 @@ class Partner(models.Model):
def _generate_access_token(self):
return uuid.uuid4().hex
def _send_selection_email(self, partner, division_companies):
def _send_selection_email(self, division_companies):
self.ensure_one()
# Generate a token and save it to the partner
access_token = self._generate_access_token()
partner.write({'access_token': access_token})
print(f'partner id: {self.id}')
self.write({'access_token': access_token})
# Now include the token in the links
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
links = {
company.id: f'{base_url}/select_division_company?partner_id={partner.id}&access_token={access_token}&division_id={company.id}'
for company in division_companies
company.name: (f'{base_url}/select_division_company?partner_id={self.id}&access_token={access_token}&division_id={company.id}') for company in division_companies
}
print(f'links: {links}')
# Render the email template and send the email
template = self.env.ref('bemade_partner_email_domain.mail_template_selection_email')
template.with_context(links=links).send_mail(partner.id, force_send=True)
template = self.env.ref('bemade_partner_email_domain.email_template_select_parent')
template.with_context(links=links).send_mail(self.id, force_send=True)
@api.onchange('email')
# @api.onchange('email')
def _check_parent_from_email_domain(self):
for rec in self:
if rec.parent_id:
@ -50,17 +52,8 @@ class Partner(models.Model):
# If the current email domain matches the main domain, return True
company_domain = self.env['res.partner'].search([('email_domain', 'ilike', email_domain)])
if company_domain:
if company_domain.domain_identifier:
division_company = self.env['res.partner'].search([('parent_id', '=', company_domain.id),
('is_company', '=', True)])
# need to send an email to the new partner asking him to select his parent in the liste
# of company under domain identifier
if division_company:
# Send an email to the partner with the division company selection link
if len(division_company) > 1:
self._send_selection_email(self, division_company)
else:
rec.parent_id = division_company[0].id
if len(company_domain) > 1:
rec._send_selection_email(company_domain)
else:
rec.parent_id = company_domain.id
return

View file

@ -6,14 +6,16 @@
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<field name="company_type" position="after">
<label for="domain_identifier" string="Domain identifier" attrs="{'invisible': ['|', ('is_company', '=', False), ('is_subdivision', '=', True)]}"/>
<field name="domain_identifier" attrs="{'invisible': ['|', ('is_company', '=', False), ('is_subdivision', '=', True)]}"/>
<label for="is_subdivision" string="Division" attrs="{'invisible': ['|', ('is_company', '=', False), ('domain_identifier', '=', True)]}"/>
<field name="is_subdivision" attrs="{'invisible': ['|', ('is_company', '=', False), ('domain_identifier', '=', True)]}"/>
<label for="is_subdivision" string="Division" attrs="{'invisible': [('is_company', '=', False)]}"/>
<field name="is_subdivision" attrs="{'invisible': [('is_company', '=', False)]}"/>
</field>
<field name="website" position="before">
<field name="email_domain" attrs="{'invisible': [('is_company', '=', False)]}"/>
</field>
<field name="parent_id" position="attributes">
<attribute name="attrs">{'invisible': [('is_company','=', True),('is_subdivision','=', False)]}
</attribute>
</field>
</field>
</record>
</odoo>