mirror of
https://github.com/bringout/oca-ocb-crm.git
synced 2026-04-25 07:52:02 +02:00
19.0 vanilla
This commit is contained in:
parent
dc68f80d3f
commit
7221b9ac46
610 changed files with 135477 additions and 161677 deletions
|
|
@ -1,18 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from psycopg2 import OperationalError
|
||||
|
||||
from odoo import _, api, fields, models, tools
|
||||
from odoo import _, api, fields, models, modules, tools
|
||||
from odoo.addons.iap.tools import iap_tools
|
||||
from odoo.tools import OrderedSet
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Lead(models.Model):
|
||||
class CrmLead(models.Model):
|
||||
_inherit = 'crm.lead'
|
||||
|
||||
iap_enrich_done = fields.Boolean(string='Enrichment done', help='Whether IAP service for lead enrichment based on email has been performed on this lead.')
|
||||
|
|
@ -27,20 +25,22 @@ class Lead(models.Model):
|
|||
lead.show_enrich_button = True
|
||||
|
||||
@api.model
|
||||
def _iap_enrich_leads_cron(self):
|
||||
timeDelta = fields.datetime.now() - datetime.timedelta(hours=1)
|
||||
def _iap_enrich_leads_cron(self, enrich_hours_delay=24, batch_size=50):
|
||||
timeDelta = self.env.cr.now() - datetime.timedelta(hours=enrich_hours_delay)
|
||||
# Get all leads not lost nor won (lost: active = False)
|
||||
leads = self.search([
|
||||
('iap_enrich_done', '=', False),
|
||||
('reveal_id', '=', False),
|
||||
'|', ('probability', '<', 100), ('probability', '=', False),
|
||||
('create_date', '>', timeDelta)
|
||||
('email_from', '!=', False),
|
||||
('reveal_id', '=', False),
|
||||
('create_date', '>', timeDelta),
|
||||
('active', '=', True),
|
||||
])
|
||||
leads.iap_enrich(from_cron=True)
|
||||
leads.iap_enrich(batch_size=batch_size)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
leads = super(Lead, self).create(vals_list)
|
||||
leads = super().create(vals_list)
|
||||
enrich_mode = self.env['ir.config_parameter'].sudo().get_param('crm.iap.lead.enrich.setting', 'auto')
|
||||
if enrich_mode == 'auto':
|
||||
cron = self.env.ref('crm_iap_enrich.ir_cron_lead_enrichment', raise_if_not_found=False)
|
||||
|
|
@ -48,73 +48,111 @@ class Lead(models.Model):
|
|||
cron._trigger()
|
||||
return leads
|
||||
|
||||
def iap_enrich(self, from_cron=False):
|
||||
# Split self in a list of sub-recordsets or 50 records to prevent timeouts
|
||||
batches = [self[index:index + 50] for index in range(0, len(self), 50)]
|
||||
for leads in batches:
|
||||
def iap_enrich(self, *, batch_size=50):
|
||||
from_cron = bool(self.env.context.get('cron_id'))
|
||||
send_notification = not from_cron
|
||||
|
||||
def process_leads(leads):
|
||||
lead_emails = {}
|
||||
with self._cr.savepoint():
|
||||
try:
|
||||
self._cr.execute(
|
||||
"SELECT 1 FROM {} WHERE id in %(lead_ids)s FOR UPDATE NOWAIT".format(self._table),
|
||||
{'lead_ids': tuple(leads.ids)}, log_exceptions=False)
|
||||
for lead in leads:
|
||||
# If lead is lost, active == False, but is anyway removed from the search in the cron.
|
||||
if lead.probability == 100 or lead.iap_enrich_done:
|
||||
continue
|
||||
# Skip if no email (different from wrong email leading to no email_normalized)
|
||||
if not lead.email_from:
|
||||
continue
|
||||
|
||||
normalized_email = tools.email_normalize(lead.email_from)
|
||||
if not normalized_email:
|
||||
lead.message_post_with_view(
|
||||
'crm_iap_enrich.mail_message_lead_enrich_no_email',
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
continue
|
||||
|
||||
email_domain = normalized_email.split('@')[1]
|
||||
# Discard domains of generic email providers as it won't return relevant information
|
||||
if email_domain in iap_tools._MAIL_PROVIDERS:
|
||||
lead.write({'iap_enrich_done': True})
|
||||
lead.message_post_with_view(
|
||||
'crm_iap_enrich.mail_message_lead_enrich_notfound',
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
else:
|
||||
lead_emails[lead.id] = email_domain
|
||||
|
||||
if lead_emails:
|
||||
try:
|
||||
iap_response = self.env['iap.enrich.api']._request_enrich(lead_emails)
|
||||
except iap_tools.InsufficientCreditError:
|
||||
_logger.info('Sent batch %s enrich requests: failed because of credit', len(lead_emails))
|
||||
if not from_cron:
|
||||
self.env['iap.account']._send_iap_bus_notification(
|
||||
service_name='reveal',
|
||||
title=_("Not enough credits for Lead Enrichment"),
|
||||
error_type='credit')
|
||||
# Since there are no credits left, there is no point to process the other batches
|
||||
break
|
||||
except Exception as e:
|
||||
if not from_cron:
|
||||
self.env['iap.account']._send_iap_bus_notification(
|
||||
service_name='reveal',
|
||||
error_type="exception",
|
||||
title=_('Sent batch %s enrich requests: failed with exception %s', len(lead_emails), e))
|
||||
_logger.info('Sent batch %s enrich requests: failed with exception %s', len(lead_emails), e)
|
||||
else:
|
||||
if not from_cron:
|
||||
self.env['iap.account']._send_iap_bus_notification(
|
||||
service_name='reveal',
|
||||
title=_("The leads/opportunities have successfully been enriched"))
|
||||
_logger.info('Sent batch %s enrich requests: success', len(lead_emails))
|
||||
self._iap_enrich_from_response(iap_response)
|
||||
except OperationalError:
|
||||
_logger.error('A batch of leads could not be enriched :%s', repr(leads))
|
||||
for lead in leads:
|
||||
# If lead is lost, active == False, but is anyway removed from the search in the cron.
|
||||
if lead.probability == 100 or lead.iap_enrich_done:
|
||||
continue
|
||||
# Commit processed batch to avoid complete rollbacks and therefore losing credits.
|
||||
if not self.env.registry.in_test_mode():
|
||||
self.env.cr.commit()
|
||||
# Skip if no email (different from wrong email leading to no email_normalized)
|
||||
if not lead.email_from:
|
||||
continue
|
||||
|
||||
normalized_email = tools.email_normalize(lead.email_from)
|
||||
if not normalized_email:
|
||||
lead.write({'iap_enrich_done': True})
|
||||
lead.message_post_with_source(
|
||||
'crm_iap_enrich.mail_message_lead_enrich_no_email',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
continue
|
||||
|
||||
email_domain = normalized_email.split('@')[1]
|
||||
# Discard domains of generic email providers as it won't return relevant information
|
||||
if email_domain in iap_tools._MAIL_PROVIDERS:
|
||||
lead.write({'iap_enrich_done': True})
|
||||
lead.message_post_with_source(
|
||||
'crm_iap_enrich.mail_message_lead_enrich_notfound',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
else:
|
||||
lead_emails[lead.id] = email_domain
|
||||
if not lead_emails:
|
||||
return
|
||||
|
||||
try:
|
||||
iap_response = self.env['iap.enrich.api']._request_enrich(lead_emails)
|
||||
except iap_tools.InsufficientCreditError:
|
||||
_logger.info('Lead enrichment failed because of insufficient credit')
|
||||
if send_notification:
|
||||
self.env['iap.account']._send_no_credit_notification(
|
||||
service_name='reveal',
|
||||
title=_("Not enough credits for Lead Enrichment"))
|
||||
raise
|
||||
except Exception as e:
|
||||
if send_notification:
|
||||
self.env['iap.account']._send_error_notification(
|
||||
message=_('An error occurred during lead enrichment'))
|
||||
_logger.info('An error occurred during lead enrichment: %s', e)
|
||||
return
|
||||
else:
|
||||
if send_notification:
|
||||
self.env['iap.account']._send_success_notification(
|
||||
message=_("The leads/opportunities have successfully been enriched"))
|
||||
_logger.info('Batch of %s leads successfully enriched', len(lead_emails))
|
||||
self._iap_enrich_from_response(iap_response)
|
||||
|
||||
if from_cron:
|
||||
self.env['ir.cron']._commit_progress(remaining=len(self))
|
||||
all_lead_ids = OrderedSet(self.ids)
|
||||
while all_lead_ids:
|
||||
leads = self.browse(all_lead_ids).try_lock_for_update(limit=batch_size)
|
||||
if not leads:
|
||||
_logger.error('A batch of leads could not be enriched (locked): %s', repr(self.browse(all_lead_ids)))
|
||||
# all are locked, schedule the cron later when the records might be unlocked
|
||||
self.env.ref('crm_iap_enrich.ir_cron_lead_enrichment')._trigger(self.env.cr.now() + datetime.timedelta(minutes=5))
|
||||
if from_cron:
|
||||
# mark the cron as fully done to prevent immediate reschedule
|
||||
self.env['ir.cron']._commit_progress(remaining=0)
|
||||
break
|
||||
all_lead_ids -= set(leads._ids)
|
||||
|
||||
if from_cron:
|
||||
# Using commit progress for processed leads
|
||||
try:
|
||||
process_leads(leads)
|
||||
time_left = self.env['ir.cron']._commit_progress(len(leads))
|
||||
except iap_tools.InsufficientCreditError:
|
||||
# Since there are no credits left, there is no point to process the other batches
|
||||
# set remaining=0 to avoid being called again
|
||||
self.env['ir.cron']._commit_progress(remaining=0)
|
||||
break
|
||||
except Exception:
|
||||
self.env.cr.rollback()
|
||||
_logger.error('A batch of leads could not be enriched: %s', repr(leads))
|
||||
time_left = self.env['ir.cron']._commit_progress(len(leads))
|
||||
if not time_left:
|
||||
break
|
||||
else:
|
||||
# Commit processed batch to avoid complete rollbacks and therefore losing credits.
|
||||
try:
|
||||
if modules.module.current_test:
|
||||
with self.env.cr.savepoint():
|
||||
process_leads(leads)
|
||||
else:
|
||||
process_leads(leads)
|
||||
self.env.cr.commit()
|
||||
except iap_tools.InsufficientCreditError:
|
||||
# Since there are no credits left, there is no point to process the other batches
|
||||
break
|
||||
except Exception:
|
||||
if not modules.module.current_test:
|
||||
self.env.cr.rollback()
|
||||
_logger.error('A batch of leads could not be enriched: %s', repr(leads))
|
||||
|
||||
@api.model
|
||||
def _iap_enrich_from_response(self, iap_response):
|
||||
|
|
@ -126,7 +164,10 @@ class Lead(models.Model):
|
|||
iap_data = iap_response.get(str(lead.id))
|
||||
if not iap_data:
|
||||
lead.write({'iap_enrich_done': True})
|
||||
lead.message_post_with_view('crm_iap_enrich.mail_message_lead_enrich_notfound', subtype_id=self.env.ref('mail.mt_note').id)
|
||||
lead.message_post_with_source(
|
||||
'crm_iap_enrich.mail_message_lead_enrich_notfound',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
continue
|
||||
|
||||
values = {'iap_enrich_done': True}
|
||||
|
|
@ -138,8 +179,6 @@ class Lead(models.Model):
|
|||
|
||||
if not lead.phone and iap_data.get('phone_numbers'):
|
||||
values['phone'] = iap_data['phone_numbers'][0]
|
||||
if not lead.mobile and iap_data.get('phone_numbers') and len(iap_data['phone_numbers']) > 1:
|
||||
values['mobile'] = iap_data['phone_numbers'][1]
|
||||
if not lead.country_id and iap_data.get('country_code'):
|
||||
country = self.env['res.country'].search([('code', '=', iap_data['country_code'].upper())])
|
||||
values['country_id'] = country.id
|
||||
|
|
@ -156,14 +195,14 @@ class Lead(models.Model):
|
|||
|
||||
template_values = iap_data
|
||||
template_values['flavor_text'] = _("Lead enriched based on email address")
|
||||
lead.message_post_with_view(
|
||||
lead.message_post_with_source(
|
||||
'iap_mail.enrich_company',
|
||||
values=template_values,
|
||||
subtype_id=self.env.ref('mail.mt_note').id
|
||||
render_values=template_values,
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
|
||||
def _merge_get_fields_specific(self):
|
||||
return {
|
||||
** super(Lead, self)._merge_get_fields_specific(),
|
||||
** super()._merge_get_fields_specific(),
|
||||
'iap_enrich_done': lambda fname, leads: any(lead.iap_enrich_done for lead in leads),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue