19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:53 +01:00
parent dc68f80d3f
commit 7221b9ac46
610 changed files with 135477 additions and 161677 deletions

View file

@ -2,12 +2,12 @@ from math import floor, log10
from odoo import api, models
class CRMHelpers(models.Model):
class CrmIapLeadHelpers(models.Model):
_name = 'crm.iap.lead.helpers'
_description = 'Helper methods for crm_iap_mine modules'
@api.model
def notify_no_more_credit(self, service_name, model_name, notification_parameter):
def _notify_no_more_credit(self, service_name, model_name, notification_parameter):
"""
Notify about the number of credit.
In order to avoid to spam people each hour, an ir.config_parameter is set
@ -31,26 +31,29 @@ class CRMHelpers(models.Model):
@api.model
def lead_vals_from_response(self, lead_type, team_id, tag_ids, user_id, company_data, people_data):
country_id = self.env['res.country'].search([('code', '=', company_data['country_code'])]).id
website_url = 'https://www.%s' % company_data['domain'] if company_data['domain'] else False
country_id = company_data.get('country_id')
if not country_id:
country_id = self.env['res.country'].search([('code', '=', company_data['country_code'])]).id
website_url = 'https://%s' % company_data['domain'] if company_data.get('domain') else False
lead_vals = {
# Lead vals from record itself
'type': lead_type,
'team_id': team_id,
'tag_ids': [(6, 0, tag_ids)],
'user_id': user_id,
'reveal_id': company_data['clearbit_id'],
'reveal_id': company_data.get('duns') or company_data.get('clearbit_id', ''),
# Lead vals from data
'name': company_data['name'] or company_data['domain'],
'partner_name': company_data['legal_name'] or company_data['name'],
'name': company_data.get('name', '') or company_data.get('domain', ''),
'partner_name': company_data.get('name', ''),
'email_from': next(iter(company_data.get('email', [])), ''),
'phone': company_data['phone'] or (company_data['phone_numbers'] and company_data['phone_numbers'][0]) or '',
'phone': company_data.get('phone') or next(iter(company_data.get('phone_numbers', [])), ''),
'website': website_url,
'street': company_data['location'],
'city': company_data['city'],
'zip': company_data['postal_code'],
'street': company_data.get('street') or company_data.get('location', ''),
'street2': company_data.get('street2'),
'city': company_data.get('city', ''),
'zip': company_data.get('zip') or company_data.get('postal_code', ''),
'country_id': country_id,
'state_id': self._find_state_id(company_data['state_code'], country_id),
'state_id': self._find_state_id(company_data.get('state_code'), country_id),
}
# If type is people then add first contact in lead data

View file

@ -15,6 +15,7 @@ class CrmIapLeadIndustry(models.Model):
color = fields.Integer(string='Color Index')
sequence = fields.Integer('Sequence')
_sql_constraints = [
('name_uniq', 'unique (name)', 'Industry name already exists!'),
]
_name_uniq = models.Constraint(
'unique (name)',
'Industry name already exists!',
)

View file

@ -3,9 +3,10 @@
import logging
from odoo import api, fields, models, _
from odoo import api, fields, models, _, release
from odoo.addons.iap.tools import iap_tools
from odoo.exceptions import UserError
from odoo.tools import is_html_empty
_logger = logging.getLogger(__name__)
@ -19,7 +20,7 @@ CREDIT_PER_COMPANY = 1
CREDIT_PER_CONTACT = 1
class CRMLeadMiningRequest(models.Model):
class CrmIapLeadMiningRequest(models.Model):
_name = 'crm.iap.lead.mining.request'
_description = 'CRM Lead Mining Request'
@ -46,7 +47,6 @@ class CRMLeadMiningRequest(models.Model):
# Lead / Opportunity Data
lead_type = fields.Selection([('lead', 'Leads'), ('opportunity', 'Opportunities')], string='Type', required=True, default=_default_lead_type)
display_lead_label = fields.Char(compute='_compute_display_lead_label')
team_id = fields.Many2one(
'crm.team', string='Sales Team', ondelete="set null",
domain="[('use_opportunities', '=', True)]", readonly=False, compute='_compute_team_id', store=True)
@ -76,36 +76,32 @@ class CRMLeadMiningRequest(models.Model):
lead_contacts_credits = fields.Char(compute='_compute_tooltip', readonly=True)
lead_total_credits = fields.Char(compute='_compute_tooltip', readonly=True)
@api.depends('lead_type', 'lead_number')
def _compute_display_lead_label(self):
selection_description_values = {
e[0]: e[1] for e in self._fields['lead_type']._description_selection(self.env)}
for request in self:
lead_type = selection_description_values[request.lead_type]
request.display_lead_label = '%s %s' % (request.lead_number, lead_type)
@api.onchange('lead_number', 'contact_number')
def _compute_tooltip(self):
for record in self:
company_credits = CREDIT_PER_COMPANY * record.lead_number
contact_credits = CREDIT_PER_CONTACT * record.contact_number
total_contact_credits = contact_credits * record.lead_number
record.lead_contacts_credits = _("Up to %d additional credits will be consumed to identify %d contacts per company.") % (contact_credits*company_credits, record.contact_number)
record.lead_credits = _('%d credits will be consumed to find %d companies.') % (company_credits, record.lead_number)
record.lead_total_credits = _("This makes a total of %d credits for this request.") % (total_contact_credits + company_credits)
record.lead_contacts_credits = _(
"Up to %(credit_count)d additional credits will be consumed to identify %(contact_count)d contacts per company.",
credit_count=contact_credits * company_credits,
contact_count=record.contact_number,
)
record.lead_credits = _(
"%(credit_count)d credits will be consumed to find %(company_count)d companies.",
credit_count=company_credits,
company_count=record.lead_number,
)
record.lead_total_credits = _("This makes a total of %d credits for this request.", total_contact_credits + company_credits)
@api.depends('lead_ids.lead_mining_request_id')
def _compute_lead_count(self):
if self.ids:
leads_data = self.env['crm.lead']._read_group(
[('lead_mining_request_id', 'in', self.ids)],
['lead_mining_request_id'], ['lead_mining_request_id'])
else:
leads_data = []
mapped_data = dict(
(m['lead_mining_request_id'][0], m['lead_mining_request_id_count'])
for m in leads_data)
leads_data = self.env['crm.lead']._read_group(
[('lead_mining_request_id', 'in', self.ids)],
['lead_mining_request_id'], ['__count'])
mapped_data = {
lead_mining_request.id: count
for lead_mining_request, count in leads_data}
for request in self:
request.lead_count = mapped_data.get(request.id, 0)
@ -185,21 +181,30 @@ class CRMLeadMiningRequest(models.Model):
self.company_size_max = self.company_size_min
@api.model
def get_empty_list_help(self, help_string):
def get_empty_list_help(self, help_message):
if not is_html_empty(help_message):
return help_message
help_title = _('Create a Lead Mining Request')
sub_title = _('Generate new leads based on their country, industry, size, etc.')
return '<p class="o_view_nocontent_smiling_face">%s</p><p class="oe_view_nocontent_alias">%s</p>' % (help_title, sub_title)
return super().get_empty_list_help(
f'<p class="o_view_nocontent_smiling_face">{help_title}</p><p class="oe_view_nocontent_alias">{sub_title}</p>'
)
def _prepare_iap_payload(self):
"""
This will prepare the data to send to the server
"""
self.ensure_one()
payload = {'lead_number': self.lead_number,
'search_type': self.search_type,
'countries': self.country_ids.mapped('code')}
if self.state_ids:
payload['states'] = self.state_ids.mapped('code')
payload = {
'lead_number': self.lead_number,
'search_type': self.search_type,
'countries': [{
'code': country.code,
'states': self.state_ids.filtered(lambda state: state in country.state_ids).mapped('code'),
} for country in self.country_ids],
}
if self.filter_on_size:
payload.update({'company_size_min': self.company_size_min,
'company_size_max': self.company_size_max})
@ -232,27 +237,34 @@ class CRMLeadMiningRequest(models.Model):
server_payload = self._prepare_iap_payload()
reveal_account = self.env['iap.account'].get('reveal')
dbuuid = self.env['ir.config_parameter'].sudo().get_param('database.uuid')
reveal_ids = [lead['reveal_id'] for lead in self.env['crm.lead'].search_read([('reveal_id', '!=', False)], ['reveal_id'])]
params = {
'account_token': reveal_account.account_token,
'dbuuid': dbuuid,
'data': server_payload
'account_token': reveal_account.sudo().account_token,
'db_uuid': dbuuid,
'query': server_payload,
'db_version': release.version,
'db_lang': self.env.lang,
'country_code': self.env.company.country_id.code,
'reveal_ids': reveal_ids,
}
try:
response = self._iap_contact_mining(params, timeout=300)
if response.get('credit_error'):
self.error_type = 'credits'
self.state = 'error'
return False
if not response.get('data'):
self.error_type = 'no_result'
return False
return response['data']
except iap_tools.InsufficientCreditError as e:
self.error_type = 'credits'
self.state = 'error'
return False
except Exception as e:
raise UserError(_("Your request could not be executed: %s", e))
def _iap_contact_mining(self, params, timeout=300):
endpoint = self.env['ir.config_parameter'].sudo().get_param('reveal.endpoint', DEFAULT_ENDPOINT) + '/iap/clearbit/1/lead_mining_request'
endpoint = self.env['ir.config_parameter'].sudo().get_param('reveal.endpoint', DEFAULT_ENDPOINT) + '/api/dnb/1/search_by_criteria'
return iap_tools.iap_jsonrpc(endpoint, params=params, timeout=timeout)
def _create_leads_from_response(self, result):
@ -261,25 +273,33 @@ class CRMLeadMiningRequest(models.Model):
lead_vals_list = []
messages_to_post = {}
for data in result:
country = self.env['res.country'].search([('code', '=', data['country_code'])])
lead_vals_list.append(self._lead_vals_from_response(data))
template_values = data['company_data']
template_values = data
template_values.update({
'flavor_text': _("Opportunity created by Odoo Lead Generation"),
'people_data': data.get('people_data'),
'country': country.name,
'zip_code': data.get('zip'),
'country_id': country.id,
})
messages_to_post[data['company_data']['clearbit_id']] = template_values
messages_to_post[data['duns']] = template_values
leads = self.env['crm.lead'].create(lead_vals_list)
for lead in leads:
if messages_to_post.get(lead.reveal_id):
lead.message_post_with_view('iap_mail.enrich_company', values=messages_to_post[lead.reveal_id], subtype_id=self.env.ref('mail.mt_note').id)
lead.message_post_with_source(
'iap_mail.enrich_company',
render_values=messages_to_post[lead.reveal_id],
subtype_xmlid='mail.mt_note',
)
# Methods responsible for format response data into valid odoo lead data
@api.model
def _lead_vals_from_response(self, data):
self.ensure_one()
company_data = data.get('company_data')
people_data = data.get('people_data')
company_data = data
people_data = []
lead_vals = self.env['crm.iap.lead.helpers'].lead_vals_from_response(self.lead_type, self.team_id.id, self.tag_ids.ids, self.user_id.id, company_data, people_data)
lead_vals['lead_mining_request_id'] = self.id
return lead_vals
@ -313,7 +333,7 @@ class CRMLeadMiningRequest(models.Model):
'target': 'new',
'type': 'ir.actions.act_window',
'res_id': self.id,
'context': dict(self.env.context, edit=True, form_view_initial_mode='edit')
'context': dict(self.env.context, edit=True)
}
else:
# will reload the form view and show the error message on top

View file

@ -4,7 +4,7 @@
from odoo import api, fields, models
class PeopleRole(models.Model):
class CrmIapLeadRole(models.Model):
""" CRM Reveal People Roles for People """
_name = 'crm.iap.lead.role'
_description = 'People Role'
@ -13,10 +13,11 @@ class PeopleRole(models.Model):
reveal_id = fields.Char(required=True)
color = fields.Integer(string='Color Index')
_sql_constraints = [
('name_uniq', 'unique (name)', 'Role name already exists!'),
]
_name_uniq = models.Constraint(
'unique (name)',
'Role name already exists!',
)
@api.depends('name')
def name_get(self):
return [(role.id, role.name.replace('_', ' ').title()) for role in self]
def _compute_display_name(self):
for role in self:
role.display_name = (role.name or '').replace('_', ' ').title()

View file

@ -4,7 +4,7 @@
from odoo import api, fields, models
class PeopleSeniority(models.Model):
class CrmIapLeadSeniority(models.Model):
""" Seniority for People Rules """
_name = 'crm.iap.lead.seniority'
_description = 'People Seniority'
@ -12,10 +12,12 @@ class PeopleSeniority(models.Model):
name = fields.Char(string='Name', required=True, translate=True)
reveal_id = fields.Char(required=True)
_sql_constraints = [
('name_uniq', 'unique (name)', 'Name already exists!'),
]
_name_uniq = models.Constraint(
'unique (name)',
'Name already exists!',
)
@api.depends('name')
def name_get(self):
return [(seniority.id, seniority.name.replace('_', ' ').title()) for seniority in self]
def _compute_display_name(self):
for seniority in self:
seniority.display_name = (seniority.name or '').replace('_', ' ').title()

View file

@ -1,13 +1,23 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
from odoo import fields, models, _
class Lead(models.Model):
class CrmLead(models.Model):
_inherit = 'crm.lead'
lead_mining_request_id = fields.Many2one('crm.iap.lead.mining.request', string='Lead Mining Request', index='btree_not_null')
def _merge_get_fields(self):
return super(Lead, self)._merge_get_fields() + ['lead_mining_request_id']
return super()._merge_get_fields() + ['lead_mining_request_id']
def action_generate_leads(self):
return {
"name": _("Need help reaching your target?"),
"type": "ir.actions.act_window",
"res_model": "crm.iap.lead.mining.request",
"target": "new",
"views": [[False, "form"]],
"context": {"is_modal": True},
}