1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import logging
import threading
from odoo.addons.iap.tools import iap_tools
from odoo import api, fields, models, _
from odoo.tools.mail import email_domain_extract, url_domain_extract
_logger = logging.getLogger(__name__)
COMPANY_AC_TIMEOUT = 5
class ResCompany(models.Model):
_name = 'res.company'
_inherit = 'res.company'
partner_gid = fields.Integer('Company database ID', related="partner_id.partner_gid", inverse="_inverse_partner_gid", store=True)
iap_enrich_auto_done = fields.Boolean('Enrich Done')
def _inverse_partner_gid(self):
for company in self:
company.partner_id.partner_gid = company.partner_gid
@api.model_create_multi
def create(self, vals_list):
res = super().create(vals_list)
if not getattr(threading.current_thread(), 'testing', False):
res.iap_enrich_auto()
return res
@api.model
def _get_view(self, view_id=None, view_type='form', **options):
arch, view = super()._get_view(view_id, view_type, **options)
if view_type == 'form':
for node in arch.xpath("//field[@name='name' or @name='vat']"):
node.set('widget', 'field_partner_autocomplete')
return arch, view
def iap_enrich_auto(self):
""" Enrich company. This method should be called by automatic processes
and a protection is added to avoid doing enrich in a loop. """
if self.env.user._is_system():
for company in self.filtered(lambda company: not company.iap_enrich_auto_done):
company._enrich()
self.iap_enrich_auto_done = True
return True
def _enrich(self):
""" This method calls the partner autocomplete service from IAP to enrich
partner related fields of the company.
:return bool: either done, either failed """
self.ensure_one()
_logger.info("Starting enrich of company %s (%s)", self.name, self.id)
company_domain = self._get_company_domain()
if not company_domain:
return False
company_data = self.env['res.partner'].enrich_company(company_domain, False, self.vat, timeout=COMPANY_AC_TIMEOUT)
if company_data.get('error'):
return False
additional_data = company_data.pop('additional_info', False)
# Keep only truthy values that are not already set on the target partner
# Erase image_1920 even if something is in it. Indeed as partner_autocomplete is probably installed as a
# core app (mail -> iap -> partner_autocomplete auto install chain) it is unlikely that people already
# updated their company logo.
self.env['res.partner']._iap_replace_logo(company_data)
company_data = {field: value for field, value in company_data.items()
if field in self.partner_id._fields and value and (field == 'image_1920' or not self.partner_id[field])}
# for company and childs: from state_id / country_id display_name like to IDs
company_data.update(self._enrich_extract_m2o_id(company_data, ['state_id', 'country_id']))
if company_data.get('child_ids'):
company_data['child_ids'] = [
dict(child_data, **self._enrich_extract_m2o_id(child_data, ['state_id', 'country_id']))
for child_data in company_data['child_ids']
]
# handle o2m values, e.g. {'bank_ids': ['acc_number': 'BE012012012', 'acc_holder_name': 'MyWebsite']}
self._enrich_replace_o2m_creation(company_data)
self.partner_id.write(company_data)
if additional_data:
template_values = json.loads(additional_data)
template_values['flavor_text'] = _("Company auto-completed by Odoo Partner Autocomplete Service")
self.partner_id.message_post_with_source(
'iap_mail.enrich_company',
render_values=template_values,
subtype_xmlid='mail.mt_note',
)
return True
def _enrich_extract_m2o_id(self, iap_data, m2o_fields):
""" Extract m2O ids from data (because of res.partner._format_data_company) """
extracted_data = {}
for m2o_field in m2o_fields:
relation_data = iap_data.get(m2o_field)
if relation_data and isinstance(relation_data, dict):
extracted_data[m2o_field] = relation_data.get('id', False)
return extracted_data
def _enrich_replace_o2m_creation(self, iap_data):
for o2m_field, values in iap_data.items():
if isinstance(values, list):
commands = [(
0, 0, create_value
) for create_value in values if isinstance(create_value, dict)]
if commands:
iap_data[o2m_field] = commands
else:
iap_data.pop(o2m_field, None)
return iap_data
def _get_company_domain(self):
""" Extract the company domain to be used by IAP services.
The domain is extracted from the website or the email information.
e.g:
- www.info.proximus.be -> proximus.be
- info@proximus.be -> proximus.be """
self.ensure_one()
company_domain = email_domain_extract(self.email) if self.email else False
if company_domain and company_domain not in iap_tools._MAIL_PROVIDERS:
return company_domain
company_domain = url_domain_extract(self.website) if self.website else False
if not company_domain or company_domain in ['localhost', 'example.com']:
return False
return company_domain
|