res_partner.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. import base64
  4. import json
  5. import logging
  6. import requests
  7. from odoo import api, fields, models, tools, _
  8. _logger = logging.getLogger(__name__)
  9. PARTNER_AC_TIMEOUT = 5
  10. class ResPartner(models.Model):
  11. _name = 'res.partner'
  12. _inherit = 'res.partner'
  13. partner_gid = fields.Integer('Company database ID')
  14. additional_info = fields.Char('Additional info')
  15. @api.model
  16. def _iap_replace_location_codes(self, iap_data):
  17. country_code, country_name = iap_data.pop('country_code', False), iap_data.pop('country_name', False)
  18. state_code, state_name = iap_data.pop('state_code', False), iap_data.pop('state_name', False)
  19. country, state = None, None
  20. if country_code:
  21. country = self.env['res.country'].search([['code', '=ilike', country_code]])
  22. if not country and country_name:
  23. country = self.env['res.country'].search([['name', '=ilike', country_name]])
  24. if country:
  25. if state_code:
  26. state = self.env['res.country.state'].search([
  27. ('country_id', '=', country.id), ('code', '=ilike', state_code)
  28. ], limit=1)
  29. if not state and state_name:
  30. state = self.env['res.country.state'].search([
  31. ('country_id', '=', country.id), ('name', '=ilike', state_name)
  32. ], limit=1)
  33. else:
  34. _logger.info('Country code not found: %s', country_code)
  35. if country:
  36. iap_data['country_id'] = {'id': country.id, 'display_name': country.display_name}
  37. if state:
  38. iap_data['state_id'] = {'id': state.id, 'display_name': state.display_name}
  39. return iap_data
  40. @api.model
  41. def _iap_replace_logo(self, iap_data):
  42. if iap_data.get('logo'):
  43. try:
  44. iap_data['image_1920'] = base64.b64encode(
  45. requests.get(iap_data['logo'], timeout=PARTNER_AC_TIMEOUT).content
  46. )
  47. except Exception:
  48. iap_data['image_1920'] = False
  49. finally:
  50. iap_data.pop('logo')
  51. # avoid keeping falsy images (may happen that a blank page is returned that leads to an incorrect image)
  52. if iap_data['image_1920']:
  53. try:
  54. tools.base64_to_image(iap_data['image_1920'])
  55. except Exception:
  56. iap_data.pop('image_1920')
  57. return iap_data
  58. @api.model
  59. def _format_data_company(self, iap_data):
  60. self._iap_replace_location_codes(iap_data)
  61. if iap_data.get('child_ids'):
  62. child_ids = []
  63. for child in iap_data.get('child_ids'):
  64. child_ids.append(self._iap_replace_location_codes(child))
  65. iap_data['child_ids'] = child_ids
  66. if iap_data.get('additional_info'):
  67. iap_data['additional_info'] = json.dumps(iap_data['additional_info'])
  68. return iap_data
  69. @api.model
  70. def autocomplete(self, query, timeout=15):
  71. suggestions, _ = self.env['iap.autocomplete.api']._request_partner_autocomplete('search', {
  72. 'query': query,
  73. }, timeout=timeout)
  74. if suggestions:
  75. results = []
  76. for suggestion in suggestions:
  77. results.append(self._format_data_company(suggestion))
  78. return results
  79. else:
  80. return []
  81. @api.model
  82. def enrich_company(self, company_domain, partner_gid, vat, timeout=15):
  83. response, error = self.env['iap.autocomplete.api']._request_partner_autocomplete('enrich', {
  84. 'domain': company_domain,
  85. 'partner_gid': partner_gid,
  86. 'vat': vat,
  87. }, timeout=timeout)
  88. if response and response.get('company_data'):
  89. result = self._format_data_company(response.get('company_data'))
  90. else:
  91. result = {}
  92. if response and response.get('credit_error'):
  93. result.update({
  94. 'error': True,
  95. 'error_message': 'Insufficient Credit'
  96. })
  97. elif error:
  98. result.update({
  99. 'error': True,
  100. 'error_message': error
  101. })
  102. return result
  103. @api.model
  104. def read_by_vat(self, vat, timeout=15):
  105. vies_vat_data, _ = self.env['iap.autocomplete.api']._request_partner_autocomplete('search_vat', {
  106. 'vat': vat,
  107. }, timeout=timeout)
  108. if vies_vat_data:
  109. return [self._format_data_company(vies_vat_data)]
  110. else:
  111. return []
  112. @api.model
  113. def _is_company_in_europe(self, country_code):
  114. country = self.env['res.country'].search([('code', '=ilike', country_code)])
  115. if country:
  116. country_id = country.id
  117. europe = self.env.ref('base.europe')
  118. if not europe:
  119. europe = self.env["res.country.group"].search([('name', '=', 'Europe')], limit=1)
  120. if not europe or country_id not in europe.country_ids.ids:
  121. return False
  122. return True
  123. def _is_vat_syncable(self, vat):
  124. vat_country_code = vat[:2]
  125. partner_country_code = self.country_id.code if self.country_id else ''
  126. return self._is_company_in_europe(vat_country_code) and (partner_country_code == vat_country_code or not partner_country_code)
  127. def _is_synchable(self):
  128. already_synched = self.env['res.partner.autocomplete.sync'].search([('partner_id', '=', self.id), ('synched', '=', True)])
  129. return self.is_company and self.partner_gid and not already_synched
  130. def _update_autocomplete_data(self, vat):
  131. self.ensure_one()
  132. if vat and self._is_synchable() and self._is_vat_syncable(vat):
  133. self.env['res.partner.autocomplete.sync'].sudo().add_to_queue(self.id)
  134. @api.model_create_multi
  135. def create(self, vals_list):
  136. partners = super(ResPartner, self).create(vals_list)
  137. if len(vals_list) == 1:
  138. partners._update_autocomplete_data(vals_list[0].get('vat', False))
  139. if partners.additional_info:
  140. template_values = json.loads(partners.additional_info)
  141. template_values['flavor_text'] = _("Partner created by Odoo Partner Autocomplete Service")
  142. partners.message_post_with_view(
  143. 'iap_mail.enrich_company',
  144. values=template_values,
  145. subtype_id=self.env.ref('mail.mt_note').id,
  146. )
  147. partners.write({'additional_info': False})
  148. return partners
  149. def write(self, values):
  150. res = super(ResPartner, self).write(values)
  151. if len(self) == 1:
  152. self._update_autocomplete_data(values.get('vat', False))
  153. return res