diff --git a/.tx/config b/.tx/config
index 871ba9e412fd7a7701a03419d38e1ec0a7dc6e6f..840fb1e8ed05d33aa8c286150d0ad13a929bd312 100644
--- a/.tx/config
+++ b/.tx/config
@@ -462,6 +462,11 @@ file_filter = addons/pad_project/i18n/<lang>.po
 source_file = addons/pad_project/i18n/pad_project.pot
 source_lang = en
 
+[odoo-12.partner_autocomplete]
+file_filter = partner_autocomplete/i18n/<lang>.po
+source_file = partner_autocomplete/i18n/partner_autocomplete.pot
+source_lang = en
+
 [odoo-12.payment]
 file_filter = addons/payment/i18n/<lang>.po
 source_file = addons/payment/i18n/payment.pot
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index c42a1edddbab804322838a257c2aae8fdddd8447..7847f238e087bc85bd135b893747fd7b1f6c6653 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -279,7 +279,7 @@ class AccountInvoice(models.Model):
              "means direct payment.")
     partner_id = fields.Many2one('res.partner', string='Partner', change_default=True,
         readonly=True, states={'draft': [('readonly', False)]},
-        track_visibility='always')
+        track_visibility='always', help="You can find a contact by its Name, TIN, Email or Internal Reference.")
     vendor_bill_id = fields.Many2one('account.invoice', string='Vendor Bill',
         help="Auto-complete from a past bill.")
     payment_term_id = fields.Many2one('account.payment.term', string='Payment Terms', oldname='payment_term',
diff --git a/addons/account/views/account_invoice_view.xml b/addons/account/views/account_invoice_view.xml
index 0cd723f1ff907cb58a391bbacabc0aec2631b3fb..1c7ea86e3aeb6bf1b0779e824e54c05e18b446cd 100644
--- a/addons/account/views/account_invoice_view.xml
+++ b/addons/account/views/account_invoice_view.xml
@@ -283,7 +283,8 @@
                     <group>
                         <group>
                             <field string="Vendor" name="partner_id"
-                              context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1, 'default_company_type': 'company'}"
+                              widget="res_partner_many2one"
+                              context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1, 'default_is_company': True, 'show_vat': True}"
                               domain="[('supplier', '=', True)]"/>
                             <field name="reference" string="Vendor Reference"/>
                             <field name="vendor_bill_id" attrs="{'invisible': [('state','not in',['draft'])]}"
@@ -436,7 +437,8 @@
                     <group>
                         <group>
                             <field string="Customer" name="partner_id"
-                                context="{'search_default_customer':1, 'show_address': 1, 'default_company_type': 'company'}"
+                                widget="res_partner_many2one"
+                                context="{'search_default_customer':1, 'show_address': 1, 'default_is_company': True, 'show_vat': True}"
                                 options='{"always_reload": True, "no_quick_create": True}'
                                 domain="[('customer', '=', True)]" required="1"/>
                             <field name="payment_term_id"/>
diff --git a/addons/account/views/partner_view.xml b/addons/account/views/partner_view.xml
index 84279d3878fff2d14647c01f720fb6010170b03f..152356fcb659097fffae2d9e271318b5ebe8f397 100644
--- a/addons/account/views/partner_view.xml
+++ b/addons/account/views/partner_view.xml
@@ -200,6 +200,7 @@
                                         <field name="sequence" widget="handle"/>
                                         <field name="bank_id"/>
                                         <field name="acc_number"/>
+                                        <field name="acc_holder_name" invisible="1"/>
                                     </tree>
                                 </field>
                                 <button type="action" class="btn-link"
diff --git a/addons/base_setup/models/res_config_settings.py b/addons/base_setup/models/res_config_settings.py
index de5037a2245fd2bf08cba13fc7425b4e1703b7a2..d23737db9013acf4785a075f88cff2a100637756 100644
--- a/addons/base_setup/models/res_config_settings.py
+++ b/addons/base_setup/models/res_config_settings.py
@@ -31,6 +31,7 @@ class ResConfigSettings(models.TransientModel):
     module_pad = fields.Boolean("Collaborative Pads")
     module_voip = fields.Boolean("Asterisk (VoIP)")
     module_web_unsplash = fields.Boolean("Unsplash Image Library")
+    module_partner_autocomplete = fields.Boolean("Auto-populate company data")
     company_share_partner = fields.Boolean(string='Share partners to all companies',
         help="Share your partners to all companies defined in your instance.\n"
              " * Checked : Partners are visible for every companies, even if a company is defined on the partner.\n"
diff --git a/addons/base_setup/views/res_config_settings_views.xml b/addons/base_setup/views/res_config_settings_views.xml
index 95515c8ab97289d256b1ca1daea33bc5e8a64f12..de090d491d5eeab63e799065b9f05158e6cf4e5b 100644
--- a/addons/base_setup/views/res_config_settings_views.xml
+++ b/addons/base_setup/views/res_config_settings_views.xml
@@ -244,6 +244,17 @@
                                     </div>
                                 </div>
                             </div>
+                            <div class="col-xs-12 col-md-6 o_setting_box" title="When populating your address book, Odoo provides a list of matching companies. When selecting one item, the company data and logo are auto-filled.">
+                                <div class="o_setting_left_pane">
+                                    <field name="module_partner_autocomplete"/>
+                                </div>
+                                <div class="o_setting_right_pane" id="partner_autocomplete_settings">
+                                    <label for="module_partner_autocomplete"/>
+                                    <div class="text-muted">
+                                        Autocomplete company data (name, logo, address, etc.)
+                                    </div>
+                                </div>
+                            </div>
                         </div>
                     </div>
                 </xpath>
diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py
index 177d6aa8048b37aacaef44ea00b91604d42165b0..df5a0e0cfce5188150d0e10479a368a202c4ba68 100644
--- a/addons/crm/models/crm_lead.py
+++ b/addons/crm/models/crm_lead.py
@@ -65,7 +65,7 @@ class Lead(models.Model):
 
     name = fields.Char('Opportunity', required=True, index=True)
     partner_id = fields.Many2one('res.partner', string='Customer', track_visibility='onchange', track_sequence=1, index=True,
-        help="Linked partner (optional). Usually created when converting the lead.")
+        help="Linked partner (optional). Usually created when converting the lead. You can find a partner by its Name, TIN, Email or Internal Reference.")
     active = fields.Boolean('Active', default=True, track_visibility=True)
     date_action_last = fields.Datetime('Last Action', readonly=True)
     email_from = fields.Char('Email', help="Email address of the contact", track_visibility='onchange', track_sequence=4, index=True)
diff --git a/addons/crm/models/res_config_settings.py b/addons/crm/models/res_config_settings.py
index c2ca5a60735244a528f41e2090c6daee554557a2..33386434f2a8b2a32930c22b519aee85a3d8aa64 100644
--- a/addons/crm/models/res_config_settings.py
+++ b/addons/crm/models/res_config_settings.py
@@ -11,7 +11,6 @@ class ResConfigSettings(models.TransientModel):
     generate_lead_from_alias = fields.Boolean('Manual Assignation of Emails', config_parameter='crm.generate_lead_from_alias')
     group_use_lead = fields.Boolean(string="Leads", implied_group='crm.group_use_lead')
     module_crm_phone_validation = fields.Boolean("Phone Formatting")
-    module_web_clearbit = fields.Boolean("Customer Autocomplete")
 
     def _find_default_lead_alias_id(self):
         alias = self.env.ref('crm.mail_alias_lead_info', False)
diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml
index f4a5ba6ca19a35e65fb4320ecc130d4d5b4031d3..04b29c6153c3af0cd38080cacf846e1d7b3618d1 100644
--- a/addons/crm/views/crm_lead_views.xml
+++ b/addons/crm/views/crm_lead_views.xml
@@ -68,7 +68,9 @@
                         <group>
                             <!-- Preload all the partner's information -->
                             <field name="partner_id" string="Customer"
-                                context="{'default_name': contact_name, 'default_street': street, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_function': function, 'default_phone': phone, 'default_mobile': mobile, 'default_email': email_from, 'default_user_id': user_id, 'default_team_id': team_id, 'default_website': website}" groups="base.group_no_one"/>
+                                    widget="res_partner_many2one"
+                                    context="{'default_name': contact_name, 'default_street': street, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_function': function, 'default_phone': phone, 'default_mobile': mobile, 'default_email': email_from, 'default_user_id': user_id, 'default_team_id': team_id, 'default_website': website, 'show_vat': True}"
+                                    groups="base.group_no_one"/>
                             <field name="partner_name" string="Company Name"/>
                             <label for="street" string="Address"/>
                             <div class="o_address_format">
@@ -240,7 +242,7 @@
                         <group>
                             <group>
                                 <field name="name" string="Opportunity Title" placeholder="e.g. Customer Deal"/>
-                                <field name="partner_id" domain="[('customer', '=', True)]" context="{'search_default_customer': 1}"/>
+                                <field name="partner_id" widget="res_partner_many2one" domain="[('customer', '=', True)]" context="{'search_default_customer': 1, 'show_vat': True}"/>
                                 <field name="partner_name" invisible="1"/>
                                 <field name="street" invisible="1"/>
                                 <field name="street2" invisible="1"/>
@@ -298,7 +300,7 @@
                 <form>
                     <group>
                         <field name="name"/>
-                        <field name="partner_id" domain="[('customer', '=', True)]" context="{'search_default_customer': 1}"/>
+                        <field name="partner_id" widget="res_partner_many2one" domain="[('customer', '=', True)]" context="{'search_default_customer': 1, 'show_vat': True}"/>
                         <field name="planned_revenue" widget="monetary" options="{'currency_field': 'company_currency'}"/>
                         <field name="company_currency" invisible="1"/>
                         <field name="company_id" invisible="1"/>
@@ -370,7 +372,7 @@
                                         </div>
                                     </div>
                                 </div>
-                                <div class="oe_clear"></div>
+                                <div class="oe_clear"/>
                             </div>
                         </t>
                     </templates>
@@ -493,6 +495,7 @@
                         <group>
                             <group>
                                 <field name="partner_id"
+                                    widget="res_partner_many2one"
                                     string="Customer" domain="[('customer', '=', True)]"
                                     context="{'search_default_customer': 1,
                                         'default_name': partner_name, 'default_street': street,
@@ -501,7 +504,10 @@
                                         'default_country_id': country_id, 'default_function': function,
                                         'default_phone': phone, 'default_mobile': mobile,
                                         'default_email': email_from,
-                                        'default_user_id': user_id, 'default_team_id': team_id, 'default_website': website}"/>
+                                        'default_user_id': user_id, 'default_team_id': team_id, 'default_website': website,
+                                        'show_vat': True,
+                                    }"
+                                />
                                 <field name="is_blacklisted" invisible="1"/>
                                 <field name="partner_is_blacklisted" invisible="1"/>
                                 <label for="email_from" class="oe_inline"/>
diff --git a/addons/crm/views/res_config_settings_views.xml b/addons/crm/views/res_config_settings_views.xml
index a32b08a63f2d42613e02e11d92cc3e5d5ab662d3..e37b01336a4a3af9e23a8818f1e03d0bf08d94c1 100644
--- a/addons/crm/views/res_config_settings_views.xml
+++ b/addons/crm/views/res_config_settings_views.xml
@@ -66,17 +66,6 @@
                                 </div>
                             </div>
                         </div>
-                        <div class="col-12 col-lg-6 o_setting_box" title="When populating your address book, Odoo relies on Clearbit’s API to provide you with a list of matching contacts or companies.When selecting one item, the partner name, logo and website get automatically set.">
-                            <div class="o_setting_left_pane">
-                                <field name="module_web_clearbit" widget="upgrade_boolean"/>
-                            </div>
-                            <div class="o_setting_right_pane">
-                                <label for="module_web_clearbit"/>
-                                <div class="text-muted">
-                                    Look up company information (name, logo, etc.)
-                                </div>
-                            </div>
-                        </div>
                     </div>
                 </div>
             </xpath>
diff --git a/addons/crm/wizard/crm_lead_to_opportunity_views.xml b/addons/crm/wizard/crm_lead_to_opportunity_views.xml
index c12587a5fb011188289ea4dc2696e7efdfa8fe98..97a06862ab14ca296d23ba445fef4ffc0e7e6d7e 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity_views.xml
+++ b/addons/crm/wizard/crm_lead_to_opportunity_views.xml
@@ -32,7 +32,7 @@
                     <group name="action" attrs="{'invisible': [('name', '!=', 'convert')]}" string="Customers" col="1">
                         <field name="action" nolabel="1" widget="radio"/>
                         <group col="2">
-                            <field name="partner_id" domain="[('customer', '=', True)]" context="{'search_default_customer': 1}" attrs="{'required': [('action', '=', 'exist')], 'invisible':[('action','!=','exist')]}"/>
+                            <field name="partner_id" widget="res_partner_many2one" domain="[('customer', '=', True)]" context="{'search_default_customer': 1, 'show_vat': True}" attrs="{'required': [('action', '=', 'exist')], 'invisible':[('action','!=','exist')]}"/>
                         </group>
                     </group>
                     <footer>
@@ -79,7 +79,9 @@
                         <field name="action" class="oe_inline" widget="radio"/>
                         <group col="2">
                             <field name="partner_id"
+                                widget="res_partner_many2one"
                                 attrs="{'required': [('action', '=', 'exist')], 'invisible':[('action','!=','exist')]}"
+                                context="{'show_vat': True}"
                                 class="oe_inline"/>
                         </group>
                     </group>
diff --git a/addons/iap/models/iap.py b/addons/iap/models/iap.py
index ea97914da1bd01e06f1c402fd0ac908dc79cd805..8d6b85e6d73164e9ee836991044ab6f6e87716d1 100644
--- a/addons/iap/models/iap.py
+++ b/addons/iap/models/iap.py
@@ -145,7 +145,7 @@ class IapAccount(models.Model):
     service_name = fields.Char()
     account_token = fields.Char(default=lambda s: uuid.uuid4().hex)
     company_id = fields.Many2one('res.company', default=lambda self: self.env.user.company_id)
-    insufficient_credit= fields.Boolean('Insufficient credits', default=False)
+    insufficient_credit = fields.Boolean('Insufficient credits', default=False)
 
     @api.model
     def get(self, service_name):
diff --git a/addons/iap/static/src/js/crash_manager.js b/addons/iap/static/src/js/crash_manager.js
index 93ccf8bee95335bb87a0c27fe1cedf2bf1c11554..59b07af1294a74084eca8875e2c6f05933651ab5 100644
--- a/addons/iap/static/src/js/crash_manager.js
+++ b/addons/iap/static/src/js/crash_manager.js
@@ -52,11 +52,11 @@ CrashManager.include({
                     $content: content,
                     buttons: [{
                         text: self._getButtonMessage(error_data.trial),
-                        classes: "btn-primary",
+                        classes : "btn-primary",
                         click: function () {
                             window.open(url, '_blank');
                         },
-                        close: true,
+                        close:true,
                     }, {
                         text: _t("Cancel"),
                         close: true,
diff --git a/addons/partner_autocomplete/__init__.py b/addons/partner_autocomplete/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..cde864bae21a11c0e4f50067aa46b4c497549b4c
--- /dev/null
+++ b/addons/partner_autocomplete/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from . import models
diff --git a/addons/partner_autocomplete/__manifest__.py b/addons/partner_autocomplete/__manifest__.py
new file mode 100644
index 0000000000000000000000000000000000000000..eeb767f2258e1e0cb3a442661d5d31c2fdb6062d
--- /dev/null
+++ b/addons/partner_autocomplete/__manifest__.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "Partner Autocomplete",
+    'summary': """
+        Auto-complete partner companies' data""",
+    'description': """
+       Auto-complete partner companies' data
+    """,
+    'author': "Odoo SA",
+    'category': 'Tools',
+    'version': '1.0',
+
+    'depends': ['web', 'mail', 'iap'],
+    'data': [
+        'security/ir.model.access.csv',
+        'views/partner_autocomplete_assets.xml',
+        'views/additional_info_template.xml',
+        'views/res_partner_views.xml',
+        'views/res_company_views.xml',
+        'views/res_config_settings_views.xml',
+        'data/cron.xml',
+    ],
+    'qweb': [
+        'static/src/xml/partner_autocomplete.xml',
+    ],
+    'auto_install': True,
+}
diff --git a/addons/partner_autocomplete/data/cron.xml b/addons/partner_autocomplete/data/cron.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f382d10f7f2ecb10073b809633a594c420c7f39f
--- /dev/null
+++ b/addons/partner_autocomplete/data/cron.xml
@@ -0,0 +1,12 @@
+<odoo>
+    <record id="ir_cron_partner_autocomplete" model="ir.cron">
+        <field name="name">Partner Autocomplete : Sync with remote DB</field>
+        <field name="model_id" ref="model_res_partner_autocomplete_sync"/>
+        <field name="state">code</field>
+        <field name="code">model.start_sync()</field>
+        <field name="interval_number">1</field>
+        <field name="interval_type">minutes</field>
+        <field name="numbercall">-1</field>
+        <field eval="False" name="doall"/>
+    </record>
+</odoo>
diff --git a/addons/partner_autocomplete/i18n/partner_autocomplete.pot b/addons/partner_autocomplete/i18n/partner_autocomplete.pot
index 1817e359bc71f4df68f52063d892bc0e687da480..2a7e7ec09648dd0d5caf4d0697e92e444c845712 100644
--- a/addons/partner_autocomplete/i18n/partner_autocomplete.pot
+++ b/addons/partner_autocomplete/i18n/partner_autocomplete.pot
@@ -6,8 +6,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Odoo Server saas~11.5\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-09-18 09:49+0000\n"
-"PO-Revision-Date: 2018-09-18 09:49+0000\n"
+"POT-Creation-Date: 2018-09-21 11:54+0000\n"
+"PO-Revision-Date: 2018-09-21 11:54+0000\n"
 "Last-Translator: <>\n"
 "Language-Team: \n"
 "MIME-Version: 1.0\n"
@@ -15,26 +15,241 @@ msgstr ""
 "Content-Transfer-Encoding: \n"
 "Plural-Forms: \n"
 
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "&amp;nbsp;&amp;nbsp;&amp;nbsp;"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Annual revenue:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Description</b><br/>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Email addresses</b><br/>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Employees:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Estimated annual revenue:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Phone numbers</b><br/>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Sector:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Social networks</b><br/>\n"
+"            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Facebook:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<b>Tech:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<br/>\n"
+"            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Crunchbase:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<br/>\n"
+"            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Linkedin:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.additional_info_template
+msgid "<br/>\n"
+"            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Twitter:</b>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.res_config_settings_view_form
+msgid "<i class=\"fa fa-arrow-right\"/>\n"
+"                        Buy more credits"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.res_config_settings_view_form
+msgid "<i class=\"fa fa-exclamation-triangle text-warning\"/> &amp;nbsp; You don't have credits to auto-complete companies' data anymore."
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.res_config_settings_view_form
+msgid "<span>&amp;times;</span>"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner__additional_info
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_users__additional_info
+msgid "Additional info"
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml:30
+#, python-format
+msgid "Buy more credits"
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml:20
+#, python-format
+msgid "Checking remaining credit ..."
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.res_config_settings_view_form
+msgid "Close"
+msgstr ""
+
 #. module: partner_autocomplete
 #: model:ir.model,name:partner_autocomplete.model_res_company
 msgid "Companies"
 msgstr ""
 
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_company__partner_gid
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner__partner_gid
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_users__partner_gid
+msgid "Company database ID"
+msgstr ""
+
 #. module: partner_autocomplete
 #: model:ir.model,name:partner_autocomplete.model_res_partner
 msgid "Contact"
 msgstr ""
 
 #. module: partner_autocomplete
-#: model_terms:ir.ui.view,arch_db:partner_autocomplete.res_company_view_form
-#: model_terms:ir.ui.view,arch_db:partner_autocomplete.view_partner_form
-#: model_terms:ir.ui.view,arch_db:partner_autocomplete.view_partner_short_form
-msgid "VAT"
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js:108
+#, python-format
+msgid "Create and Edit from Autocomplete :"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__id
+msgid "ID"
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml:23
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_config_settings__partner_autocomplete_insufficient_credit
+#, python-format
+msgid "Insufficient credit"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__synched
+msgid "Is synched"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model.fields,field_description:partner_autocomplete.field_res_partner_autocomplete_sync__partner_id
+msgid "Partner"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.actions.server,name:partner_autocomplete.ir_cron_partner_autocomplete_ir_actions_server
+#: model:ir.cron,cron_name:partner_autocomplete.ir_cron_partner_autocomplete
+#: model:ir.cron,name:partner_autocomplete.ir_cron_partner_autocomplete
+msgid "Partner Autocomplete : Sync with remote DB"
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml:8
+#, python-format
+msgid "Placeholder"
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml:26
+#, python-format
+msgid "Remaining :"
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js:22
+#, python-format
+msgid "Searching Autocomplete..."
+msgstr ""
+
+#. module: partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.view_res_partner_form_inherit_partner_autocomplete
+#: model_terms:ir.ui.view,arch_db:partner_autocomplete.view_res_partner_short_form_inherit_partner_autocomplete
+msgid "You can find a customer, a contact, etc. by its Name, TIN, Email or Internal Reference."
+msgstr ""
+
+#. module: partner_autocomplete
+#. openerp-web
+#: code:addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml:26
+#, python-format
+msgid "credits"
+msgstr ""
+
+#. module: partner_autocomplete
+#: model:ir.model,name:partner_autocomplete.model_res_config_settings
+msgid "res.config.settings"
 msgstr ""
 
 #. module: partner_autocomplete
-#: model_terms:ir.ui.view,arch_db:partner_autocomplete.view_partner_form
-#: model_terms:ir.ui.view,arch_db:partner_autocomplete.view_partner_short_form
-msgid "e.g. BE0477472701"
+#: model:ir.model,name:partner_autocomplete.model_res_partner_autocomplete_sync
+msgid "res.partner.autocomplete.sync"
 msgstr ""
 
diff --git a/addons/partner_autocomplete/models/__init__.py b/addons/partner_autocomplete/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d9eecc13d775c49809b8aff991e44dfa58f31ed
--- /dev/null
+++ b/addons/partner_autocomplete/models/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import res_partner
+from . import res_company
+from . import res_config_settings
+from . import res_partner_autocomplete_sync
diff --git a/addons/partner_autocomplete/models/res_company.py b/addons/partner_autocomplete/models/res_company.py
new file mode 100644
index 0000000000000000000000000000000000000000..e946567fcdea03e58dabae2f6989165c703d5b38
--- /dev/null
+++ b/addons/partner_autocomplete/models/res_company.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+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)
+
+    def _inverse_partner_gid(self):
+        for company in self:
+            company.partner_id.partner_gid = company.partner_gid
diff --git a/addons/partner_autocomplete/models/res_config_settings.py b/addons/partner_autocomplete/models/res_config_settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..f28046d6189d5f7463ef3e2299e8805599a95a50
--- /dev/null
+++ b/addons/partner_autocomplete/models/res_config_settings.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+
+class ResConfigSettings(models.TransientModel):
+    _inherit = 'res.config.settings'
+
+    partner_autocomplete_insufficient_credit = fields.Boolean('Insufficient credit', default=lambda self: self.env['iap.account'].get('partner_autocomplete').insufficient_credit)
+
+    @api.multi
+    def redirect_to_buy_autocmplete_credit(self):
+        return {
+            'type': 'ir.actions.act_url',
+            'url': self.env['iap.account'].get_credits_url('partner_autocomplete'),
+            'target': '_new',
+        }
diff --git a/addons/partner_autocomplete/models/res_partner.py b/addons/partner_autocomplete/models/res_partner.py
new file mode 100644
index 0000000000000000000000000000000000000000..60d5b182222d01e94bae08dc45607dff97b14b23
--- /dev/null
+++ b/addons/partner_autocomplete/models/res_partner.py
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+from odoo import api, fields, models, exceptions, _
+from odoo.addons.iap import jsonrpc
+from requests.exceptions import ConnectionError, HTTPError
+from odoo.tools import pycompat
+from odoo.addons.iap.models.iap import InsufficientCreditError
+
+_logger = logging.getLogger(__name__)
+
+PARTNER_REMOTE_URL = 'https://partner-autocomplete.odoo.com/iap/partner_autocomplete'
+
+class ResPartner(models.Model):
+    _name = 'res.partner'
+    _inherit = 'res.partner'
+
+    partner_gid = fields.Integer('Company database ID')
+    additional_info = fields.Char('Additional info')
+
+    @api.model
+    def _replace_location_code_by_id(self, record):
+        record['country_id'], record['state_id'] = self._find_country_data(
+            state_code=record.pop('state_code', False),
+            state_name=record.pop('state_name', False),
+            country_code=record.pop('country_code', False),
+            country_name=record.pop('country_name', False)
+        )
+        return record
+
+    @api.model
+    def _format_data_company(self, company):
+        self._replace_location_code_by_id(company)
+
+        if company.get('child_ids'):
+            child_ids = []
+            for child in company.get('child_ids'):
+                child_ids.append(self._replace_location_code_by_id(child))
+            company['child_ids'] = child_ids
+
+        if company.get('additional_info'):
+            company['additional_info'] = self.env.ref('partner_autocomplete.additional_info_template').render(company.get('additional_info'))
+
+        return company
+
+    @api.model
+    def _find_country_data(self, state_code, state_name, country_code, country_name):
+        country = self.env['res.country'].search([['code', '=ilike', country_code]])
+        if not country:
+            country = self.env['res.country'].search([['name', '=ilike', country_name]])
+
+        state_id = {}
+        country_id = {}
+        if country:
+            country_id = {
+                'id': country.id,
+                'display_name': country.display_name
+            }
+            if state_name or state_code:
+                state = self.env['res.country.state'].search([
+                    ('country_id', '=', country_id.get('id')),
+                    '|',
+                    ('name', '=ilike', state_name),
+                    ('code', '=ilike', state_code)
+                ], limit=1)
+
+                if state:
+                    state_id = {
+                        'id': state.id,
+                        'display_name': state.display_name
+                    }
+        else:
+            _logger.info('Country code not found: %s', country_code)
+
+        return country_id, state_id
+
+    @api.model
+    def _rpc_remote_api(self, action, params, timeout=15):
+        url = '%s/%s' % (PARTNER_REMOTE_URL, action)
+        account = self.env['iap.account'].get('partner_autocomplete')
+        params.update({
+            'db_uuid': self.env['ir.config_parameter'].sudo().get_param('database.uuid'),
+            'account_token': account.account_token,
+            'country_code': self.env.user.company_id.country_id.code,
+            'zip': self.env.user.company_id.zip,
+        })
+        try:
+            return jsonrpc(url=url, params=params, timeout=timeout), False
+        except (ConnectionError, HTTPError, exceptions.AccessError) as exception:
+            _logger.error('Autocomplete API error: %s' % str(exception))
+            return False, str(exception)
+        except InsufficientCreditError:
+            account = self.env['iap.account'].get('partner_autocomplete')
+            if account:
+                account.write({'insufficient_credit': True})
+            return False, 'Insufficient Credit'
+
+    @api.model
+    def autocomplete(self, query):
+        suggestions, error = self._rpc_remote_api('search', {
+            'query': query,
+        })
+        if suggestions:
+            results = []
+            for suggestion in suggestions:
+                results.append(suggestion)
+            return results
+        else:
+            return []
+
+    @api.model
+    def enrich_company(self, company_domain, partner_gid, vat):
+        response, error = self._rpc_remote_api('enrich', {
+            'domain': company_domain,
+            'partner_gid': partner_gid,
+            'vat': vat,
+        })
+        if response and response.get('company_data'):
+            return self._format_data_company(response.get('company_data'))
+        else:
+            return {}
+
+    @api.model
+    def read_by_vat(self, vat):
+        vies_vat_data, error = self._rpc_remote_api('search_vat', {
+            'vat': vat,
+        })
+        if vies_vat_data:
+            return [self._format_data_company(vies_vat_data)]
+        else:
+            return []
+
+    @api.model
+    def _is_company_in_europe(self, country_code):
+        country = self.env['res.country'].search([('code', '=ilike', country_code)])
+        if country:
+            country_id = country.id
+            europe = self.env.ref('base.europe')
+            if not europe:
+                europe = self.env["res.country.group"].search([('name', '=', 'Europe')], limit=1)
+            if not europe or country_id not in europe.country_ids.ids:
+                return False
+        return True
+
+    def _is_vat_syncable(self, vat):
+        vat_country_code = vat[:2]
+        partner_country_code = self.country_id and self.country_id.code
+        return self._is_company_in_europe(vat_country_code) and (partner_country_code == vat_country_code or not partner_country_code)
+
+    def _is_synchable(self):
+        already_synched = self.env['res.partner.autocomplete.sync'].search([('partner_id', '=', self.id), ('synched', '=', True)])
+        return self.is_company and self.partner_gid and not already_synched
+
+    def _update_autocomplete_data(self, vat):
+        self.ensure_one()
+        if vat and self._is_synchable() and self._is_vat_syncable(vat):
+            self.env['res.partner.autocomplete.sync'].sudo().add_to_queue(self.id)
+
+    @api.model_create_multi
+    def create(self, vals_list):
+        partners = super(ResPartner, self).create(vals_list)
+        if len(vals_list) == 1:
+            for partner, values in pycompat.izip(partners, vals_list):
+                partner._update_autocomplete_data(values.get('vat', False))
+
+                if partner.additional_info:
+                    partner.message_post(body=partner.additional_info)
+                    partner.write({'additional_info': False})
+
+        return partners
+
+    @api.multi
+    def write(self, values):
+        record = super(ResPartner, self).write(values)
+        if len(self) == 1:
+            for partner in self:
+                partner._update_autocomplete_data(values.get('vat', False))
+
+            return record
diff --git a/addons/partner_autocomplete/models/res_partner_autocomplete_sync.py b/addons/partner_autocomplete/models/res_partner_autocomplete_sync.py
new file mode 100644
index 0000000000000000000000000000000000000000..a0ae355662f1548bbe10593666b44b202728e079
--- /dev/null
+++ b/addons/partner_autocomplete/models/res_partner_autocomplete_sync.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+from odoo import api, fields, models
+
+_logger = logging.getLogger(__name__)
+
+class ResPartnerAutocompleteSync(models.Model):
+    _name = 'res.partner.autocomplete.sync'
+
+    partner_id = fields.Many2one('res.partner', string="Partner", ondelete='cascade')
+    synched = fields.Boolean('Is synched', default=False)
+
+    @api.model
+    def start_sync(self):
+        to_sync_items = self.search([('synched', '=', False)])
+        for to_sync_item in to_sync_items:
+            partner = to_sync_item.partner_id
+
+            params = {
+                'partner_gid': partner.partner_gid,
+            }
+
+            if partner.vat and partner._is_vat_syncable(partner.vat):
+                params['vat'] = partner.vat
+                result, error = partner._rpc_remote_api('update', params)
+                if error:
+                    _logger.error('Send Partner to sync failed: %s' % str(error))
+
+            to_sync_item.write({'synched': True})
+
+    def add_to_queue(self, partner_id):
+        to_sync = self.search([('partner_id', '=', partner_id)])
+        if not to_sync:
+            to_sync = self.create({'partner_id': partner_id})
+        return to_sync
diff --git a/addons/partner_autocomplete/security/ir.model.access.csv b/addons/partner_autocomplete/security/ir.model.access.csv
new file mode 100644
index 0000000000000000000000000000000000000000..67da1da8d050584377f4e465f63396bd1467a82c
--- /dev/null
+++ b/addons/partner_autocomplete/security/ir.model.access.csv
@@ -0,0 +1,5 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_partner_autocomplete_sync_all_all,res.partner.autocomplete.sync.all,model_res_partner_autocomplete_sync,,1,0,0,0
+access_partner_autocomplete_sync_portal,res.partner.autocomplete.sync.portal,model_res_partner_autocomplete_sync,base.group_portal,1,0,1,0
+access_partner_autocomplete_sync_user,res.partner.autocomplete.sync.user,model_res_partner_autocomplete_sync,base.group_user,1,1,1,0
+access_partner_autocomplete_sync_system,res.partner.autocomplete.sync.system,model_res_partner_autocomplete_sync,base.group_system,1,1,1,1
\ No newline at end of file
diff --git a/addons/partner_autocomplete/static/lib/jsvat.js b/addons/partner_autocomplete/static/lib/jsvat.js
new file mode 100644
index 0000000000000000000000000000000000000000..07dae2d3af0cccdb74bc159182a296a98f377e5c
--- /dev/null
+++ b/addons/partner_autocomplete/static/lib/jsvat.js
@@ -0,0 +1,1338 @@
+/*==================================================================
+
+Application:   Utility Function
+Author:        John Gardner
+Website:       http://www.braemoor.co.uk/software/vat.shtml
+
+Version:       V1.0
+Date:          30th July 2005
+Description:   Used to check the validity of an EU country VAT number
+
+Version:       V1.1
+Date:          3rd August 2005
+Description:   Lithuanian legal entities & Maltese check digit checks added.
+
+Version:       V1.2
+Date:          20th October 2005
+Description:   Italian checks refined (thanks Matteo Mike Peluso).
+
+Version:       V1.3
+Date:          16th November 2005
+Description:   Error in GB numbers ending in 00 fixed (thanks Guy Dawson).
+
+Version:       V1.4
+Date:          28th September 2006
+Description:   EU-type numbers added.
+
+Version:       V1.5
+Date:          1st January 2007
+Description:   Romanian and Bulgarian numbers added.
+
+Version:       V1.6
+Date:          7th January 2007
+Description:   Error with Slovenian numbers (thanks to Ales Hotko).
+
+Version:       V1.7
+Date:          10th February 2007
+Description:   Romanian check digits added.
+               Thanks to Dragu Costel for the test suite.
+
+Version:       V1.8
+Date:          3rd August 2007
+Description:   IE code modified to allow + and * in old format numbers.
+               Thanks to Antonin Moy of Sphere Solutions for pointing out the error.
+
+Version:       V1.9
+Date:          6th August 2007
+Description:   BE code modified to make a specific check that the leading character of 10 digit
+               numbers is 0 (belts and braces).
+
+Version:       V1.10
+Date:          10th August 2007
+Description:   Cypriot check digit support added.
+               Check digit validation support for non-standard UK numbers
+
+Version:       V1.11
+Date:          25th September 2007
+Description:   Spain check digit support for personal numbers.
+               Author: David Perez Carmona
+
+Version:       V1.12
+Date:          23rd November 2009
+Description:   GB code modified to take into account new style check digits.
+               Thanks to Guy Dawson of Crossflight Ltd for pointing out the necessity.
+
+Version:       V1.13
+Date:          7th July 2012
+Description:   EL, GB, SE and BE formats updated - thanks to Joost Van Biervliet of VAT Applications
+
+Version:       V.14
+Date:          8th April 2013
+Description:   BE Pattern match refined
+               BG Add check digit checks for all four types of VAT number
+               CY Pattern match improved
+               CZ Personal pattern match checking improved
+               CZ Personal check digits incorporated
+               EE improved pattern match
+               ES Physical person number checking refined
+               GB Check digit support provided for 12 digit VAT codes and range checks included
+               IT Bug removed to allow 999 and 888 issuing office codes
+               LT temporarily registered taxpayers check digit support added
+               LV Natural persons checks added
+               RO improved pattern match
+               SK improved pattern match and added check digit support
+
+               Thanks to Theo Vroom for his help in this latest release.
+
+Version:      V1.15
+Date:         15th April 2013
+              Swedish algorithm re-implemented.
+
+Version:      V1.16
+Date:         25th July 2013
+              Support for Croatian numbers added
+
+Version       V1.17
+              10th September 2013
+              Support for Norwegian MVA numbers added (yes, I know that Norway is not in the EU!)
+
+Version       V1.18
+              29th October 2013
+              Partial support for new style Irish numbers.
+              See http://www.revenue.ie/en/practitioner/ebrief/2013/no-032013.html
+              Thanks to Simon Leigh for drawing the author's attention to this.
+
+Version       V1.19
+              31st October 2013
+              Support for Serbian PBI numbers added (yes, I know that Serbia is not in the EU!)
+
+Version       V1.20
+              1st November 2013
+              Support for Swiss MWST numbers added (yes, I know that Switzerland is not in the EU!)
+
+Version       V1.21
+              16th December 2014
+              Non-critical code tidies to French and Danish regular expressions.
+              Thanks to Bill Seddon of Lyquidity Solutions
+
+Version       V1.22
+              14th January 2014
+              Non-critical code tidy to regular expression for new format Irish numbers.
+              Thanks to Olivier Reubens of UNIT4 C-Logic N.V.
+
+Version       V1.23
+              10th April 2014
+              Support for Russian INN numbers added (yes, I know that Russia is not in the EU!).
+              Thanks to Marco Cesaratto of Arki Tech, Italy
+
+Version       V1.24
+              4th June 2014
+              Check digit validation supported for Irish Type 3 numbers
+              Thanks to Olivier Reubens of UNIT4 C-Logic N.V.
+
+Version       V1.25
+              29th July 2014
+              Code improvements
+              Thanks to Sébastien Boelpaep and Nate Kerkhofs
+
+Version       V1.26
+              4th May 2015
+              Code improvements to regular expressions
+              Thanks to Robert Gust-Bardon of webcraft.ch
+
+Version       V1.27
+              3rd December 2015
+              Extend Swiss optional suffix to allow TVA and ITA
+              Thanks to Oskars Petermanis
+
+Version       V1.28
+              30th August 2016
+              Correct Swiss optional suffix to allow TVA and IVA
+              Thanks to Jan Verhaegen
+
+Version       V1.29
+              29th July 2017
+              Correct Czeck Republic checking of Individual type 2 - Special Cases
+              Thanks to Andreas Wuermser of Auer Packaging UK
+
+Parameters:    toCheck - VAT number be checked.
+
+This function checks the value of the parameter for a valid European VAT number.
+
+If the number is found to be invalid format, the function returns a value of false. Otherwise it
+returns the VAT number re-formatted.
+
+Example call:
+
+  if (checkVATNumber (myVATNumber))
+      alert ("VAT number has a valid format")
+  else
+      alert ("VAT number has invalid format");
+
+---------------------------------------------------------------------------------------------------*/
+
+var checkVATNumber = (function (){
+    // Array holds the regular expressions for the valid VAT number
+    var vatexp = new Array();
+
+    // To change the default country (e.g. from the UK to Germany - DE):
+    //    1.  Change the country code in the defCCode variable below to "DE".
+    //    2.  Remove the question mark from the regular expressions associated with the UK VAT number:
+    //        i.e. "(GB)?" -> "(GB)"
+    //    3.  Add a question mark into the regular expression associated with Germany's number
+    //        following the country code: i.e. "(DE)" -> "(DE)?"
+
+    var defCCode = "GB";
+
+    // Note - VAT codes without the "**" in the comment do not have check digit checking.
+
+    vatexp.push(/^(AT)U(\d{8})$/);                           //** Austria
+    vatexp.push(/^(BE)(0?\d{9})$/);                          //** Belgium
+    vatexp.push(/^(BG)(\d{9,10})$/);                         //** Bulgaria
+    vatexp.push(/^(CHE)(\d{9})(MWST|TVA|IVA)?$/);            //** Switzerland
+    vatexp.push(/^(CY)([0-59]\d{7}[A-Z])$/);                 //** Cyprus
+    vatexp.push(/^(CZ)(\d{8,10})(\d{3})?$/);                 //** Czech Republic
+    vatexp.push(/^(DE)([1-9]\d{8})$/);                       //** Germany
+    vatexp.push(/^(DK)(\d{8})$/);                            //** Denmark
+    vatexp.push(/^(EE)(10\d{7})$/);                          //** Estonia
+    vatexp.push(/^(EL)(\d{9})$/);                            //** Greece
+    vatexp.push(/^(ES)([A-Z]\d{8})$/);                       //** Spain (National juridical entities)
+    vatexp.push(/^(ES)([A-HN-SW]\d{7}[A-J])$/);              //** Spain (Other juridical entities)
+    vatexp.push(/^(ES)([0-9YZ]\d{7}[A-Z])$/);                //** Spain (Personal entities type 1)
+    vatexp.push(/^(ES)([KLMX]\d{7}[A-Z])$/);                 //** Spain (Personal entities type 2)
+    vatexp.push(/^(EU)(\d{9})$/);                            //** EU-type
+    vatexp.push(/^(FI)(\d{8})$/);                            //** Finland
+    vatexp.push(/^(FR)(\d{11})$/);                           //** France (1)
+    vatexp.push(/^(FR)([A-HJ-NP-Z]\d{10})$/);                // France (2)
+    vatexp.push(/^(FR)(\d[A-HJ-NP-Z]\d{9})$/);               // France (3)
+    vatexp.push(/^(FR)([A-HJ-NP-Z]{2}\d{9})$/);              // France (4)
+    vatexp.push(/^(GB)?(\d{9})$/);                           //** UK (Standard)
+    vatexp.push(/^(GB)?(\d{12})$/);                          //** UK (Branches)
+    vatexp.push(/^(GB)?(GD\d{3})$/);                         //** UK (Government)
+    vatexp.push(/^(GB)?(HA\d{3})$/);                         //** UK (Health authority)
+    vatexp.push(/^(HR)(\d{11})$/);                           //** Croatia
+    vatexp.push(/^(HU)(\d{8})$/);                            //** Hungary
+    vatexp.push(/^(IE)(\d{7}[A-W])$/);                       //** Ireland (1)
+    vatexp.push(/^(IE)([7-9][A-Z\*\+)]\d{5}[A-W])$/);        //** Ireland (2)
+    vatexp.push(/^(IE)(\d{7}[A-W][AH])$/);                   //** Ireland (3)
+    vatexp.push(/^(IT)(\d{11})$/);                           //** Italy
+    vatexp.push(/^(LV)(\d{11})$/);                           //** Latvia
+    vatexp.push(/^(LT)(\d{9}|\d{12})$/);                     //** Lithunia
+    vatexp.push(/^(LU)(\d{8})$/);                            //** Luxembourg
+    vatexp.push(/^(MT)([1-9]\d{7})$/);                       //** Malta
+    vatexp.push(/^(NL)(\d{9})B\d{2}$/);                      //** Netherlands
+    vatexp.push(/^(NO)(\d{9})$/);                            //** Norway (not EU)
+    vatexp.push(/^(PL)(\d{10})$/);                           //** Poland
+    vatexp.push(/^(PT)(\d{9})$/);                            //** Portugal
+    vatexp.push(/^(RO)([1-9]\d{1,9})$/);                     //** Romania
+    vatexp.push(/^(RU)(\d{10}|\d{12})$/);                    //** Russia
+    vatexp.push(/^(RS)(\d{9})$/);                            //** Serbia
+    vatexp.push(/^(SI)([1-9]\d{7})$/);                       //** Slovenia
+    vatexp.push(/^(SK)([1-9]\d[2346-9]\d{7})$/);             //** Slovakia Republic
+    vatexp.push(/^(SE)(\d{10}01)$/);                         //** Sweden
+
+    function checkVATNumber(toCheck) {
+        // Load up the string to check
+        var VATNumber = toCheck.toUpperCase();
+
+        // Remove spaces etc. from the VAT number to help validation
+        VATNumber = VATNumber.replace(/(\s|-|\.)+/g, '');
+
+        // Assume we're not going to find a valid VAT number
+        var valid = false;
+
+        // Check the string against the regular expressions for all types of VAT numbers
+        for (var i = 0; i < vatexp.length; i++) {
+
+            // Have we recognised the VAT number?
+            if (vatexp[i].test(VATNumber)) {
+
+                // Yes - we have
+                var cCode = RegExp.$1;                             // Isolate country code
+                var cNumber = RegExp.$2;                           // Isolate the number
+                if (cCode.length == 0) cCode = defCCode;           // Set up default country code
+
+                // Call the appropriate country VAT validation routine depending on the country code
+                if (eval(cCode + "VATCheckDigit ('" + cNumber + "')")) valid = VATNumber;
+
+                // Having processed the number, we break from the loop
+                break;
+            }
+        }
+
+        // Return with either an error or the reformatted VAT number
+        return valid;
+    }
+
+    function ATVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of an Austrian VAT number.
+
+        var total = 0;
+        var multipliers = [1, 2, 1, 2, 1, 2, 1];
+        var temp = 0;
+
+        // Extract the next digit and multiply by the appropriate multiplier.
+        for (var i = 0; i < 7; i++) {
+            temp = Number(vatnumber.charAt(i)) * multipliers[i];
+            if (temp > 9)
+                total += Math.floor(temp / 10) + temp % 10;
+            else
+                total += temp;
+        }
+
+        // Establish check digit.
+        total = 10 - (total + 4) % 10;
+        if (total == 10) total = 0;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(7, 8))
+            return true;
+        else
+            return false;
+    }
+
+    function BEVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Belgium VAT number.
+
+        // Nine digit numbers have a 0 inserted at the front.
+        if (vatnumber.length == 9) vatnumber = "0" + vatnumber;
+
+        if (vatnumber.slice(1, 2) == 0) return false;
+
+        // Modulus 97 check on last nine digits
+        if (97 - vatnumber.slice(0, 8) % 97 == vatnumber.slice(8, 10))
+            return true;
+        else
+            return false;
+    }
+
+    function BGVATCheckDigit(vatnumber) {
+        var temp, total, multipliers, i;
+
+        // Checks the check digits of a Bulgarian VAT number.
+
+        if (vatnumber.length == 9) {
+            // Check the check digit of 9 digit Bulgarian VAT numbers.
+            total = 0;
+
+            // First try to calculate the check digit using the first multipliers
+            temp = 0;
+            for (i = 0; i < 8; i++) temp += Number(vatnumber.charAt(i)) * (i + 1);
+
+            // See if we have a check digit yet
+            total = temp % 11;
+            if (total != 10) {
+                if (total == vatnumber.slice(8))
+                    return true;
+                else
+                    return false;
+            }
+
+            // We got a modulus of 10 before so we have to keep going. Calculate the new check digit using
+            // the different multipliers
+            temp = 0;
+            for (i = 0; i < 8; i++) temp += Number(vatnumber.charAt(i)) * (i + 3);
+
+            // See if we have a check digit yet. If we still have a modulus of 10, set it to 0.
+            total = temp % 11;
+            if (total == 10) total = 0;
+            if (total == vatnumber.slice(8))
+                return true;
+            else
+                return false;
+        }
+
+        // 10 digit VAT code - see if it relates to a standard physical person
+        if ((/^\d\d[0-5]\d[0-3]\d\d{4}$/).test(vatnumber)) {
+
+            // Check month
+            var month = Number(vatnumber.slice(2, 4));
+            if ((month > 0 && month < 13) || (month > 20 && month < 33) || (month > 40 && month < 53)) {
+
+                // Extract the next digit and multiply by the counter.
+                multipliers = [2, 4, 8, 5, 10, 9, 7, 3, 6];
+                total = 0;
+                for (i = 0; i < 9; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+                // Establish check digit.
+                total = total % 11;
+                if (total == 10) total = 0;
+
+                // Check to see if the check digit given is correct, If not, try next type of person
+                if (total == vatnumber.substr(9, 1)) return true;
+            }
+        }
+
+        // It doesn't relate to a standard physical person - see if it relates to a foreigner.
+
+        // Extract the next digit and multiply by the counter.
+        multipliers = [21, 19, 17, 13, 11, 9, 7, 3, 1];
+        total = 0;
+        for (i = 0; i < 9; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Check to see if the check digit given is correct, If not, try next type of person
+        if (total % 10 == vatnumber.substr(9, 1)) return true;
+
+        // Finally, if not yet identified, see if it conforms to a miscellaneous VAT number
+
+        // Extract the next digit and multiply by the counter.
+        multipliers = [4, 3, 2, 7, 6, 5, 4, 3, 2];
+        total = 0;
+        for (i = 0; i < 9; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digit.
+        total = 11 - total % 11;
+        if (total == 10) return false;
+        if (total == 11) total = 0;
+
+        // Check to see if the check digit given is correct, If not, we have an error with the VAT number
+        if (total == vatnumber.substr(9, 1))
+            return true;
+        else
+            return false;
+    }
+
+    function CHEVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Swiss VAT number.
+
+        // Extract the next digit and multiply by the counter.
+        var multipliers = [5, 4, 3, 2, 7, 6, 5, 4];
+        var total = 0;
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digit.
+        total = 11 - total % 11;
+        if (total == 10) return false;
+        if (total == 11) total = 0;
+
+        // Check to see if the check digit given is correct, If not, we have an error with the VAT number
+        if (total == vatnumber.substr(8, 1))
+            return true;
+        else
+            return false;
+    }
+
+    function CYVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Cypriot VAT number.
+
+        // Not allowed to start with '12'
+        if (Number(vatnumber.slice(0, 2) == 12)) return false;
+
+        // Extract the next digit and multiply by the counter.
+        var total = 0;
+        for (var i = 0; i < 8; i++) {
+            var temp = Number(vatnumber.charAt(i));
+            if (i % 2 == 0) {
+                switch (temp) {
+                    case 0:
+                        temp = 1;
+                        break;
+                    case 1:
+                        temp = 0;
+                        break;
+                    case 2:
+                        temp = 5;
+                        break;
+                    case 3:
+                        temp = 7;
+                        break;
+                    case 4:
+                        temp = 9;
+                        break;
+                    default:
+                        temp = temp * 2 + 3;
+                }
+            }
+            total += temp;
+        }
+
+        // Establish check digit using modulus 26, and translate to char. equivalent.
+        total = total % 26;
+        total = String.fromCharCode(total + 65);
+
+        // Check to see if the check digit given is correct
+        if (total == vatnumber.substr(8, 1))
+            return true;
+        else
+            return false;
+    }
+
+    function CZVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Czech Republic VAT number.
+
+        var total = 0;
+        var multipliers = [8, 7, 6, 5, 4, 3, 2];
+
+        var czexp = new Array();
+        czexp[0] = (/^\d{8}$/);                                       //  8 digit legal entities
+        // Note - my specification says that that the following should have a range of 0-3 in the fourth
+        // digit, but the valid number CZ395601439 did not confrm, so a range of 0-9 has been allowed.
+        czexp[1] = (/^[0-5][0-9][0|1|5|6][0-9][0-3][0-9]\d{3}$/);     //  9 digit individuals
+        czexp[2] = (/^6\d{8}$/);                                      //  9 digit individuals (Special cases)
+        czexp[3] = (/^\d{2}[0-3|5-8][0-9][0-3][0-9]\d{4}$/);          // 10 digit individuals
+        var i = 0;
+        var a;
+
+        // Legal entities
+        if (czexp[0].test(vatnumber)) {
+
+            // Extract the next digit and multiply by the counter.
+            for (i = 0; i < 7; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+            // Establish check digit.
+            total = 11 - total % 11;
+            if (total == 10) total = 0;
+            if (total == 11) total = 1;
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(7, 8))
+                return true;
+            else
+                return false;
+        }
+
+        // Individuals type 1 (Standard) - 9 digits without check digit
+        else if (czexp[1].test(vatnumber)) {
+            if (Number(vatnumber.slice(0, 2)) > 62) return false;
+            return true;
+        }
+
+        // Individuals type 2 (Special Cases) - 9 digits including check digit
+        else if (czexp[2].test(vatnumber)) {
+
+            // Extract the next digit and multiply by the counter.
+            for (i = 0; i < 7; i++) total += Number(vatnumber.charAt(i + 1)) * multipliers[i];
+
+            // Establish check digit pointer into lookup table
+            if (total % 11 == 0)
+                a = total + 11;
+            else
+                a = Math.ceil(total / 11) * 11;
+            var pointer = a - total;
+
+            // Convert calculated check digit according to a lookup table;
+            var lookup = [8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8];
+            if (lookup[pointer - 1] == vatnumber.slice(8, 9))
+                return true;
+            else
+                return false;
+        }
+
+        // Individuals type 3 - 10 digits
+        else if (czexp[3].test(vatnumber)) {
+            var temp = Number(vatnumber.slice(0, 2)) + Number(vatnumber.slice(2, 4)) + Number(vatnumber.slice(4, 6)) + Number(vatnumber.slice(6, 8)) + Number(vatnumber.slice(8));
+            if (temp % 11 == 0 && Number(vatnumber) % 11 == 0)
+                return true;
+            else
+                return false;
+        }
+
+        // else error
+        return false;
+    }
+
+    function DEVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a German VAT number.
+
+        var product = 10;
+        var sum = 0;
+        var checkdigit = 0;
+        for (var i = 0; i < 8; i++) {
+
+            // Extract the next digit and implement peculiar algorithm!.
+            sum = (Number(vatnumber.charAt(i)) + product) % 10;
+            if (sum == 0) {
+                sum = 10;
+            }
+            product = (2 * sum) % 11;
+        }
+
+        // Establish check digit.
+        if (11 - product == 10) {
+            checkdigit = 0;
+        } else {
+            checkdigit = 11 - product;
+        }
+
+        // Compare it with the last two characters of the VAT number. If the same, then it is a valid
+        // check digit.
+        if (checkdigit == vatnumber.slice(8, 9))
+            return true;
+        else
+            return false;
+    }
+
+    function DKVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Danish VAT number.
+
+        var total = 0;
+        var multipliers = [2, 7, 6, 5, 4, 3, 2, 1];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digit.
+        total = total % 11;
+
+        // The remainder should be 0 for it to be valid..
+        if (total == 0)
+            return true;
+        else
+            return false;
+    }
+
+    function EEVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of an Estonian VAT number.
+
+        var total = 0;
+        var multipliers = [3, 7, 1, 3, 7, 1, 3, 7];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits using modulus 10.
+        total = 10 - total % 10;
+        if (total == 10) total = 0;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(8, 9))
+            return true;
+        else
+            return false;
+    }
+
+    function ELVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Greek VAT number.
+
+        var total = 0;
+        var multipliers = [256, 128, 64, 32, 16, 8, 4, 2];
+
+        //eight character numbers should be prefixed with an 0.
+        if (vatnumber.length == 8) {
+            vatnumber = "0" + vatnumber;
+        }
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digit.
+        total = total % 11;
+        if (total > 9) {
+            total = 0;
+        }
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(8, 9))
+            return true;
+        else
+            return false;
+    }
+
+    function ESVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Spanish VAT number.
+
+        var total = 0;
+        var temp = 0;
+        var multipliers = [2, 1, 2, 1, 2, 1, 2];
+        var esexp = new Array();
+        esexp[0] = (/^[A-H|J|U|V]\d{8}$/);
+        esexp[1] = (/^[A-H|N-S|W]\d{7}[A-J]$/);
+        esexp[2] = (/^[0-9|Y|Z]\d{7}[A-Z]$/);
+        esexp[3] = (/^[K|L|M|X]\d{7}[A-Z]$/);
+        var i = 0;
+
+        // National juridical entities
+        if (esexp[0].test(vatnumber)) {
+
+            // Extract the next digit and multiply by the counter.
+            for (i = 0; i < 7; i++) {
+                temp = Number(vatnumber.charAt(i + 1)) * multipliers[i];
+                if (temp > 9)
+                    total += Math.floor(temp / 10) + temp % 10;
+                else
+                    total += temp;
+            }
+            // Now calculate the check digit itself.
+            total = 10 - total % 10;
+            if (total == 10) {
+                total = 0;
+            }
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(8, 9))
+                return true;
+            else
+                return false;
+        }
+
+        // Juridical entities other than national ones
+        else if (esexp[1].test(vatnumber)) {
+
+            // Extract the next digit and multiply by the counter.
+            for (i = 0; i < 7; i++) {
+                temp = Number(vatnumber.charAt(i + 1)) * multipliers[i];
+                if (temp > 9)
+                    total += Math.floor(temp / 10) + temp % 10;
+                else
+                    total += temp;
+            }
+
+            // Now calculate the check digit itself.
+            total = 10 - total % 10;
+            total = String.fromCharCode(total + 64);
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(8, 9))
+                return true;
+            else
+                return false;
+        }
+
+        // Personal number (NIF) (starting with numeric of Y or Z)
+        else if (esexp[2].test(vatnumber)) {
+            var tempnumber = vatnumber;
+            if (tempnumber.substring(0, 1) == 'Y') tempnumber = tempnumber.replace(/Y/, "1");
+            if (tempnumber.substring(0, 1) == 'Z') tempnumber = tempnumber.replace(/Z/, "2");
+            return tempnumber.charAt(8) == 'TRWAGMYFPDXBNJZSQVHLCKE'.charAt(Number(tempnumber.substring(0, 8)) % 23);
+        }
+
+        // Personal number (NIF) (starting with K, L, M, or X)
+        else if (esexp[3].test(vatnumber)) {
+            return vatnumber.charAt(8) == 'TRWAGMYFPDXBNJZSQVHLCKE'.charAt(Number(vatnumber.substring(1, 8)) % 23);
+        }
+
+        else return false;
+    }
+
+    function EUVATCheckDigit(vatnumber) {
+
+        // We know little about EU numbers apart from the fact that the first 3 digits represent the
+        // country, and that there are nine digits in total.
+        return true;
+    }
+
+    function FIVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Finnish VAT number.
+
+        var total = 0;
+        var multipliers = [7, 9, 10, 5, 8, 4, 2];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 7; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digit.
+        total = 11 - total % 11;
+        if (total > 9) {
+            total = 0;
+        }
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(7, 8))
+            return true;
+        else
+            return false;
+    }
+
+    function FRVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a French VAT number.
+
+        if (!(/^\d{11}$/).test(vatnumber)) return true;
+
+        // Extract the last nine digits as an integer.
+        var total = vatnumber.substring(2);
+
+        // Establish check digit.
+        total = (total * 100 + 12) % 97;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(0, 2))
+            return true;
+        else
+            return false;
+    }
+
+    function GBVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a UK VAT number.
+
+        var multipliers = [8, 7, 6, 5, 4, 3, 2];
+
+        // Government departments
+        if (vatnumber.substr(0, 2) == 'GD') {
+            if (vatnumber.substr(2, 3) < 500)
+                return true;
+            else
+                return false;
+        }
+
+        // Health authorities
+        if (vatnumber.substr(0, 2) == 'HA') {
+            if (vatnumber.substr(2, 3) > 499)
+                return true;
+            else
+                return false;
+        }
+
+        // Standard and commercial numbers
+        var total = 0;
+
+        // 0 VAT numbers disallowed!
+        if (Number(vatnumber.slice(0)) == 0) return false;
+
+        // Check range is OK for modulus 97 calculation
+        var no = Number(vatnumber.slice(0, 7));
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 7; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Old numbers use a simple 97 modulus, but new numbers use an adaptation of that (less 55). Our
+        // VAT number could use either system, so we check it against both.
+
+        // Establish check digits by subtracting 97 from total until negative.
+        var cd = total;
+        while (cd > 0) {
+            cd = cd - 97;
+        }
+
+        // Get the absolute value and compare it with the last two characters of the VAT number. If the
+        // same, then it is a valid traditional check digit. However, even then the number must fit within
+        // certain specified ranges.
+        cd = Math.abs(cd);
+        if (cd == vatnumber.slice(7, 9) && no < 9990001 && (no < 100000 || no > 999999) && (no < 9490001 || no > 9700000)) return true;
+
+        // Now try the new method by subtracting 55 from the check digit if we can - else add 42
+        if (cd >= 55)
+            cd = cd - 55;
+        else
+            cd = cd + 42;
+        if (cd == vatnumber.slice(7, 9) && no > 1000000)
+            return true;
+        else
+            return false;
+    }
+
+    function HRVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Croatian VAT number using ISO 7064, MOD 11-10 for check digit.
+
+        var product = 10;
+        var sum = 0;
+        var checkdigit = 0;
+
+        for (var i = 0; i < 10; i++) {
+
+            // Extract the next digit and implement the algorithm
+            sum = (Number(vatnumber.charAt(i)) + product) % 10;
+            if (sum == 0) {
+                sum = 10;
+            }
+            product = (2 * sum) % 11;
+        }
+
+        // Now check that we have the right check digit
+        if ((product + vatnumber.slice(10, 11) * 1) % 10 == 1)
+            return true;
+        else
+            return false;
+    }
+
+    function HUVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Hungarian VAT number.
+
+        var total = 0;
+        var multipliers = [9, 7, 3, 1, 9, 7, 3];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 7; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digit.
+        total = 10 - total % 10;
+        if (total == 10) total = 0;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(7, 8))
+            return true;
+        else
+            return false;
+    }
+
+    function IEVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of an Irish VAT number.
+
+        var total = 0;
+        var multipliers = [8, 7, 6, 5, 4, 3, 2];
+
+        // If the code is type 1 format, we need to convert it to the new before performing the validation.
+        if (/^\d[A-Z\*\+]/.test(vatnumber)) vatnumber = "0" + vatnumber.substring(2, 7) + vatnumber.substring(0, 1) + vatnumber.substring(7, 8);
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 7; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // If the number is type 3 then we need to include the trailing A or H in the calculation
+        if (/^\d{7}[A-Z][AH]$/.test(vatnumber)) {
+
+            // Add in a multiplier for the character A (1*9=9) or H (8*9=72)
+            if (vatnumber.charAt(8) == 'H')
+                total += 72;
+            else
+                total += 9;
+        }
+
+        // Establish check digit using modulus 23, and translate to char. equivalent.
+        total = total % 23;
+        if (total == 0)
+            total = "W";
+        else
+            total = String.fromCharCode(total + 64);
+
+        // Compare it with the eighth character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(7, 8))
+            return true;
+        else
+            return false;
+    }
+
+    function ITVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of an Italian VAT number.
+
+        var total = 0;
+        var multipliers = [1, 2, 1, 2, 1, 2, 1, 2, 1, 2];
+        var temp;
+
+        // The last three digits are the issuing office, and cannot exceed more 201, unless 999 or 888
+        if (Number(vatnumber.slice(0, 7)) == 0) return false;
+        temp = Number(vatnumber.slice(7, 10));
+        if ((temp < 1) || (temp > 201) && temp != 999 && temp != 888) return false;
+
+        // Extract the next digit and multiply by the appropriate
+        for (var i = 0; i < 10; i++) {
+            temp = Number(vatnumber.charAt(i)) * multipliers[i];
+            if (temp > 9)
+                total += Math.floor(temp / 10) + temp % 10;
+            else
+                total += temp;
+        }
+
+        // Establish check digit.
+        total = 10 - total % 10;
+        if (total > 9) {
+            total = 0;
+        }
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(10, 11))
+            return true;
+        else
+            return false;
+    }
+
+    function LTVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Lithuanian VAT number.
+        var total, multipliers, i;
+
+        // 9 character VAT numbers are for legal persons
+        if (vatnumber.length == 9) {
+
+            // 8th character must be one
+            if (!(/^\d{7}1/).test(vatnumber)) return false;
+
+            // Extract the next digit and multiply by the counter+1.
+            total = 0;
+            for (i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * (i + 1);
+
+            // Can have a double check digit calculation!
+            if (total % 11 == 10) {
+                multipliers = [3, 4, 5, 6, 7, 8, 9, 1];
+                total = 0;
+                for (i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+            }
+
+            // Establish check digit.
+            total = total % 11;
+            if (total == 10) {
+                total = 0;
+            }
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(8, 9))
+                return true;
+            else
+                return false;
+        }
+
+        // 12 character VAT numbers are for temporarily registered taxpayers
+        else {
+
+            // 11th character must be one
+            if (!(/^\d{10}1/).test(vatnumber)) return false;
+
+            // Extract the next digit and multiply by the counter+1.
+            total = 0;
+            multipliers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2];
+            for (i = 0; i < 11; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+            // Can have a double check digit calculation!
+            if (total % 11 == 10) {
+                multipliers = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4];
+                total = 0;
+                for (i = 0; i < 11; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+            }
+
+            // Establish check digit.
+            total = total % 11;
+            if (total == 10) {
+                total = 0;
+            }
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(11, 12))
+                return true;
+            else
+                return false;
+        }
+    }
+
+    function LUVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Luxembourg VAT number.
+
+        if (vatnumber.slice(0, 6) % 89 == vatnumber.slice(6, 8))
+            return true;
+        else
+            return false;
+    }
+
+    function LVVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Latvian VAT number.
+
+        // Differentiate between legal entities and natural bodies. For the latter we simply check that
+        // the first six digits correspond to valid DDMMYY dates.
+        if ((/^[0-3]/).test(vatnumber)) {
+            if ((/^[0-3][0-9][0-1][0-9]/).test(vatnumber))
+                return true;
+            else
+                return false;
+        }
+
+        else {
+
+            var total = 0;
+            var multipliers = [9, 1, 4, 8, 3, 10, 2, 5, 7, 6];
+
+            // Extract the next digit and multiply by the counter.
+            for (var i = 0; i < 10; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+            // Establish check digits by getting modulus 11.
+            if (total % 11 == 4 && vatnumber[0] == 9) total = total - 45;
+            if (total % 11 == 4)
+                total = 4 - total % 11;
+            else if (total % 11 > 4)
+                total = 14 - total % 11;
+            else if (total % 11 < 4)
+                total = 3 - total % 11;
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(10, 11))
+                return true;
+            else
+                return false;
+        }
+    }
+
+    function MTVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Maltese VAT number.
+
+        var total = 0;
+        var multipliers = [3, 4, 6, 7, 8, 9];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 6; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits by getting modulus 37.
+        total = 37 - total % 37;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(6, 8) * 1)
+            return true;
+        else
+            return false;
+    }
+
+    function NLVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Dutch VAT number.
+
+        var total = 0;
+        var multipliers = [9, 8, 7, 6, 5, 4, 3, 2];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits by getting modulus 11.
+        total = total % 11;
+        if (total > 9) {
+            total = 0;
+        }
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(8, 9))
+            return true;
+        else
+            return false;
+    }
+
+    function NOVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Norwegian VAT number.
+        // See http://www.brreg.no/english/coordination/number.html
+
+        var total = 0;
+        var multipliers = [3, 2, 7, 6, 5, 4, 3, 2];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits by getting modulus 11. Check digits > 9 are invalid
+        total = 11 - total % 11;
+        if (total == 11) {
+            total = 0;
+        }
+        if (total < 10) {
+
+            // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+            if (total == vatnumber.slice(8, 9))
+                return true;
+            else
+                return false;
+        }
+    }
+
+    function PLVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Polish VAT number.
+
+        var total = 0;
+        var multipliers = [6, 5, 7, 2, 3, 4, 5, 6, 7];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 9; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits subtracting modulus 11 from 11.
+        total = total % 11;
+        if (total > 9) {
+            total = 0;
+        }
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(9, 10))
+            return true;
+        else
+            return false;
+    }
+
+    function PTVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Portugese VAT number.
+
+        var total = 0;
+        var multipliers = [9, 8, 7, 6, 5, 4, 3, 2];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 8; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits subtracting modulus 11 from 11.
+        total = 11 - total % 11;
+        if (total > 9) {
+            total = 0;
+        }
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(8, 9))
+            return true;
+        else
+            return false;
+    }
+
+    function ROVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Romanian VAT number.
+
+        var multipliers = [7, 5, 3, 2, 1, 7, 5, 3, 2];
+
+        // Extract the next digit and multiply by the counter.
+        var VATlen = vatnumber.length;
+        multipliers = multipliers.slice(10 - VATlen);
+        var total = 0;
+        for (var i = 0; i < vatnumber.length - 1; i++) {
+            total += Number(vatnumber.charAt(i)) * multipliers[i];
+        }
+
+        // Establish check digits by getting modulus 11.
+        total = (10 * total) % 11;
+        if (total == 10) total = 0;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (total == vatnumber.slice(vatnumber.length - 1, vatnumber.length))
+            return true;
+        else
+            return false;
+    }
+
+    function RSVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Serbian VAT number using ISO 7064, MOD 11-10 for check digit.
+
+        var product = 10;
+        var sum = 0;
+        var checkdigit = 0;
+
+        for (var i = 0; i < 8; i++) {
+
+            // Extract the next digit and implement the algorithm
+            sum = (Number(vatnumber.charAt(i)) + product) % 10;
+            if (sum == 0) {
+                sum = 10;
+            }
+            product = (2 * sum) % 11;
+        }
+
+        // Now check that we have the right check digit
+        if ((product + vatnumber.slice(8, 9) * 1) % 10 == 1)
+            return true;
+        else
+            return false;
+    }
+
+    function RUVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Russian INN number
+        // See http://russianpartner.biz/test_inn.html for algorithm
+
+        var i;
+
+        // 10 digit INN numbers
+        if (vatnumber.length == 10) {
+            var total = 0;
+            var multipliers = [2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
+            for (i = 0; i < 10; i++) {
+                total += Number(vatnumber.charAt(i)) * multipliers[i];
+            }
+            total = total % 11;
+            if (total > 9) {
+                total = total % 10;
+            }
+
+            // Compare it with the last character of the VAT number. If it is the same, then it's valid
+            if (total == vatnumber.slice(9, 10))
+                return true;
+            else
+                return false;
+
+            // 12 digit INN numbers
+        } else if (vatnumber.length == 12) {
+            var total1 = 0;
+            var multipliers1 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
+            var total2 = 0;
+            var multipliers2 = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
+
+            for (i = 0; i < 11; i++) total1 += Number(vatnumber.charAt(i)) * multipliers1[i];
+            total1 = total1 % 11;
+            if (total1 > 9) {
+                total1 = total1 % 10;
+            }
+
+            for (i = 0; i < 11; i++) total2 += Number(vatnumber.charAt(i)) * multipliers2[i];
+            total2 = total2 % 11;
+            if (total2 > 9) {
+                total2 = total2 % 10;
+            }
+
+            // Compare the first check with the 11th character and the second check with the 12th and last
+            // character of the VAT number. If they're both the same, then it's valid
+            if ((total1 == vatnumber.slice(10, 11)) && (total2 == vatnumber.slice(11, 12)))
+                return true;
+            else
+                return false;
+        }
+    }
+
+    function SEVATCheckDigit(vatnumber) {
+        var i;
+
+        // Calculate R where R = R1 + R3 + R5 + R7 + R9, and Ri = INT(Ci/5) + (Ci*2) modulo 10
+        var R = 0;
+        var digit;
+        for (i = 0; i < 9; i = i + 2) {
+            digit = Number(vatnumber.charAt(i));
+            R += Math.floor(digit / 5) + ((digit * 2) % 10);
+        }
+
+        // Calculate S where S = C2 + C4 + C6 + C8
+        var S = 0;
+        for (i = 1; i < 9; i = i + 2) S += Number(vatnumber.charAt(i));
+
+        // Calculate the Check Digit
+        var cd = (10 - (R + S) % 10) % 10;
+
+        // Compare it with the last character of the VAT number. If it's the same, then it's valid.
+        if (cd == vatnumber.slice(9, 10))
+            return true;
+        else
+            return false;
+    }
+
+    function SIVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Slovenian VAT number.
+
+        var total = 0;
+        var multipliers = [8, 7, 6, 5, 4, 3, 2];
+
+        // Extract the next digit and multiply by the counter.
+        for (var i = 0; i < 7; i++) total += Number(vatnumber.charAt(i)) * multipliers[i];
+
+        // Establish check digits using modulus 11
+        total = 11 - total % 11;
+        if (total == 10) {
+            total = 0;
+        }
+
+        // Compare the number with the last character of the VAT number. If it is the
+        // same, then it's a valid check digit.
+        if (total != 11 && total == vatnumber.slice(7, 8))
+            return true;
+        else
+            return false;
+    }
+
+    function SKVATCheckDigit(vatnumber) {
+
+        // Checks the check digits of a Slovakian VAT number.
+
+        // Check that the modulus of the whole VAT number is 0 - else error
+        if (Number(vatnumber % 11) == 0)
+            return true;
+        else
+            return false;
+    }
+
+    return checkVATNumber;
+})();
\ No newline at end of file
diff --git a/addons/partner_autocomplete/static/src/js/iap_credit_checker_widget.js b/addons/partner_autocomplete/static/src/js/iap_credit_checker_widget.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab25dab00290683fa6d7cff265ffb92541af6987
--- /dev/null
+++ b/addons/partner_autocomplete/static/src/js/iap_credit_checker_widget.js
@@ -0,0 +1,94 @@
+odoo.define('iap.credit.checker', function (require) {
+'use strict';
+
+var widgetRegistry = require('web.widget_registry');
+var Widget = require('web.Widget');
+
+var core = require('web.core');
+var rpc = require('web.rpc');
+
+var QWeb = core.qweb;
+
+var IAPCreditChecker = Widget.extend({
+    className: 'o_field_iap_credit_checker',
+
+    /**
+     * @constructor
+     * Prepares the basic rendering of edit mode by setting the root to be a
+     * div.dropdown.open.
+     * @see FieldChar.init
+     */
+    init: function (parent, data, options) {
+        this._super.apply(this, arguments);
+        this.service_name = options.attrs.service_name;
+    },
+
+    /**
+     * @override
+     */
+    start: function () {
+        this.$widget = $(QWeb.render('partner_autocomplete.iap_credit_checker'));
+        this.$loading = this.$widget.find('.loading');
+        this.$sufficient = this.$widget.find('.sufficient');
+        this.$insufficient = this.$widget.find('.insufficient');
+        this.$buyLink = this.$widget.find('.oe_link');
+
+        this.$widget.appendTo(this.$el);
+
+        this._getLink();
+        this._getCredits();
+    },
+
+    //--------------------------------------------------------------------------
+    // Private
+    //--------------------------------------------------------------------------
+    _getCredits: function () {
+        var self = this;
+        this._showLoading();
+
+        return rpc.query({
+            model: 'iap.account',
+            method: 'get_credits',
+            args: [this.service_name],
+        }, {
+            shadow: true,
+        }).then(function (credit) {
+            if (credit) self._showSufficient(credit);
+            else self._showInsufficient();
+        });
+    },
+
+    _getLink: function () {
+        var self = this;
+        return rpc.query({
+            model: 'iap.account',
+            method: 'get_credits_url',
+            args: [this.service_name],
+        }, {
+            shadow: true,
+        }).then(function (url) {
+            self.$buyLink.attr('href', url);
+        });
+    },
+
+    _showLoading: function () {
+        this.$loading.show();
+        this.$sufficient.hide();
+        this.$insufficient.hide();
+    },
+    _showSufficient: function (credits) {
+        this.$loading.hide();
+        this.$sufficient.show().find('.remaining_credits').text(credits);
+        this.$insufficient.hide();
+    },
+    _showInsufficient: function () {
+        this.$loading.hide();
+        this.$sufficient.hide();
+        this.$insufficient.show();
+    },
+});
+
+widgetRegistry.add('iap_credit_checker', IAPCreditChecker);
+
+return IAPCreditChecker;
+});
diff --git a/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js b/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js
new file mode 100644
index 0000000000000000000000000000000000000000..05bd10c911447e7d620270eccfe3297ae3218c0a
--- /dev/null
+++ b/addons/partner_autocomplete/static/src/js/partner_autocomplete_core.js
@@ -0,0 +1,331 @@
+odoo.define('partner.autocomplete.core', function (require) {
+'use strict';
+
+var rpc = require('web.rpc');
+var concurrency = require('web.concurrency');
+
+return {
+    _dropPreviousOdoo: new concurrency.DropPrevious(),
+    _dropPreviousClearbit: new concurrency.DropPrevious(),
+    _timeout : 1000, // Timeout for Clearbit autocomplete in ms
+    
+    //--------------------------------------------------------------------------
+    // Public
+    //--------------------------------------------------------------------------
+
+    /**
+     * Get list of companies via Autocomplete API
+     *
+     * @param {string} value
+     * @returns {Deferred}
+     * @private
+     */
+    autocomplete: function (value) {
+        value = value.trim();
+        var def = $.Deferred(),
+            isVAT = this._isVAT(value),
+            odooSuggestions = [],
+            clearbitSuggestions = [];
+
+        var odooPromise = this._getOdooSuggestions(value, isVAT).then(function (suggestions){
+            odooSuggestions = suggestions;
+        });
+
+        // Only get Clearbit suggestions if not a VAT number
+        var clearbitPromise = isVAT ? false : this._getClearbitSuggestions(value).then(function (suggestions){
+            clearbitSuggestions = suggestions;
+        });
+
+        var concatResults = function () {
+            // Add Clearbit result with Odoo result (with unique domain)
+            if (clearbitSuggestions && clearbitSuggestions.length) {
+                var websites = odooSuggestions.map(function (suggestion) {
+                    return suggestion.website;
+                });
+                clearbitSuggestions.forEach(function (suggestion) {
+                    if (websites.indexOf(suggestion.website) < 0) {
+                        odooSuggestions.push(suggestion);
+                    }
+                });
+            }
+
+            return def.resolve(odooSuggestions);
+        };
+
+        this._whenAll([odooPromise, clearbitPromise]).then(concatResults, concatResults);
+
+        return def;
+    },
+
+    /**
+     * Get enrichment data
+     *
+     * @param {Object} company
+     * @returns {Deferred}
+     * @private
+     */
+    enrichCompany: function (company) {
+        return rpc.query({
+            model: 'res.partner',
+            method: 'enrich_company',
+            args: [company.website, company.partner_gid, company.vat],
+        });
+    },
+
+    /**
+     * Get the company logo as Base 64 image from url
+     *
+     * @param {string} url
+     * @returns {Deferred}
+     * @private
+     */
+    getCompanyLogo: function (url) {
+        return this._getBase64Image(url).then(function (base64Image) {
+            // base64Image equals "data:" if image not available on given url
+            return base64Image ? base64Image.replace(/^data:image[^;]*;base64,?/, '') : false;
+        });
+    },
+
+    /**
+     * Get enriched data + logo before populating partner form
+     *
+     * @param {Object} company
+     * @returns {Deferred}
+     */
+    getCreateData: function (company) {
+        var removeUselessFields = function (company) {
+            var fields = 'label,description,domain,logo,legal_name'.split(',');
+            fields.forEach(function (field) {
+                delete company[field];
+            });
+
+            var notEmptyFields = "country_id,state_id".split(',');
+            notEmptyFields.forEach(function (field) {
+                if (!company[field]) delete company[field];
+            });
+        };
+
+        var def = $.Deferred();
+
+        // Fetch additional company info via Autocomplete Enrichment API
+        var enrichPromise = this.enrichCompany(company);
+
+        // Get logo
+        var logoPromise = company.logo ? this.getCompanyLogo(company.logo) : false;
+
+        $.when(enrichPromise, logoPromise).done(function (company_data, logo_data) {
+            if (_.isEmpty(company_data)) company_data = company;
+
+            // Delete attribute to avoid "Field_changed" errors
+            removeUselessFields(company_data);
+
+            // Assign VAT coming from parent VIES VAT query
+            if (company.vat) company_data.vat = company.vat;
+            def.resolve({
+                company: company_data,
+                logo: logo_data
+            });
+        });
+
+        return def;
+    },
+
+    /**
+     * Check connectivity
+     *
+     * @returns {boolean}
+     */
+    isOnline: function () {
+        return navigator && navigator.onLine;
+    },
+
+    /**
+     * Validate: Not empty and length > 1
+     *
+     * @param {string} search_val
+     * @param {string} onlyVAT : Only valid VAT Number search
+     * @returns {boolean}
+     * @private
+     */
+    validateSearchTerm: function (search_val, onlyVAT) {
+        if (onlyVAT) return this._isVAT(search_val);
+        else return search_val && search_val.length > 2;
+    },
+
+    //--------------------------------------------------------------------------
+    // Private
+    //--------------------------------------------------------------------------
+
+    /**
+     * Returns a deferred which will be resolved with the base64 data of the
+     * image fetched from the given url.
+     *
+     * @private
+     * @param {string} url : the url where to find the image to fetch
+     * @returns {Deferred}
+     */
+    _getBase64Image: function (url) {
+        var def = $.Deferred();
+        var xhr = new XMLHttpRequest();
+        xhr.onload = function () {
+            var reader = new FileReader();
+            reader.onloadend = function () {
+                def.resolve(reader.result);
+            };
+            reader.readAsDataURL(xhr.response);
+        };
+        xhr.open('GET', url);
+        xhr.responseType = 'blob';
+        xhr.onerror = def.reject.bind(def);
+        xhr.send();
+        return def;
+    },
+
+    /**
+     * Use Clearbit Autocomplete API to return suggestions
+     *
+     * @param {string} value
+     * @returns {Deferred}
+     * @private
+     */
+    _getClearbitSuggestions: function (value) {
+        var url = 'https://autocomplete.clearbit.com/v1/companies/suggest?query=' + value;
+        var def = $.ajax({
+            url: url,
+            dataType: 'json',
+            timeout: this._timeout,
+            success: function (suggestions) {
+                suggestions.map(function (suggestion) {
+                    suggestion.label = suggestion.name;
+                    suggestion.website = suggestion.domain;
+                    suggestion.description = suggestion.website;
+                    return suggestion;
+                });
+                return suggestions;
+            },
+        });
+
+        return this._dropPreviousClearbit.add(def);
+    },
+
+    /**
+     * Use Odoo Autocomplete API to return suggestions
+     *
+     * @param {string} value
+     * @param {boolean} isVAT
+     * @returns {Deferred}
+     * @private
+     */
+    _getOdooSuggestions: function (value, isVAT) {
+        var method = isVAT ? 'read_by_vat' : 'autocomplete';
+
+        var def = rpc.query({
+            model: 'res.partner',
+            method: method,
+            args: [value],
+        }, {
+            shadow: true,
+        }).then(function (suggestions) {
+            suggestions.map(function (suggestion) {
+                suggestion.logo = suggestion.logo || '';
+                suggestion.label = suggestion.legal_name || suggestion.name;
+                if (suggestion.vat) suggestion.description = suggestion.vat;
+                else if (suggestion.website) suggestion.description = suggestion.website;
+
+                if (suggestion.country_id && suggestion.country_id.display_name) {
+                    if (suggestion.description) suggestion.description += _.str.sprintf(' (%s)', suggestion.country_id.display_name);
+                    else suggestion.description += suggestion.country_id.display_name;
+                }
+
+                return suggestion;
+            });
+            return suggestions;
+        });
+
+        return this._dropPreviousOdoo.add(def);
+    },
+    /**
+     * Check if searched value is possibly a VAT : 2 first chars = alpha + min 5 numbers
+     *
+     * @param {string} search_val
+     * @returns {boolean}
+     * @private
+     */
+    _isVAT: function (search_val) {
+        var str = this._sanitizeVAT(search_val);
+        return checkVATNumber(str);
+    },
+
+    /**
+     * Sanitize search value by removing all not alphanumeric
+     *
+     * @param {string} search_value
+     * @returns {string}
+     * @private
+     */
+    _sanitizeVAT: function (search_value) {
+        return search_value ? search_value.replace(/[^A-Za-z0-9]/g, '') : '';
+    },
+
+    /**
+     * Utility to wait for multiple promises
+     * $.when will reject all promises whenever a promise is rejected
+     * This utility will continue
+     * Source : https://gist.github.com/fearphage/4341799
+     *
+     * @param array
+     * @returns {*}
+     * @private
+     */
+    _whenAll: function (array) {
+        var slice = [].slice;
+
+        var
+            resolveValues = arguments.length === 1 && $.isArray(array)
+                ? array
+                : slice.call(arguments)
+            , length = resolveValues.length
+            , remaining = length
+            , deferred = $.Deferred()
+            , i = 0
+            , failed = 0
+            , rejectContexts = Array(length)
+            , rejectValues = Array(length)
+            , resolveContexts = Array(length)
+            , value
+        ;
+
+        function updateFunc(index, contexts, values) {
+            return function () {
+                !(values === resolveValues) && failed++;
+                deferred.notifyWith(
+                    contexts[index] = this
+                    , values[index] = slice.call(arguments)
+                );
+                if (!(--remaining)) {
+                    deferred[(!failed ? 'resolve' : 'reject') + 'With'](contexts, values);
+                }
+            };
+        }
+
+        for (; i < length; i++) {
+            if ((value = resolveValues[i]) && $.isFunction(value.promise)) {
+                value.promise()
+                    .done(updateFunc(i, resolveContexts, resolveValues))
+                    .fail(updateFunc(i, rejectContexts, rejectValues))
+                ;
+            }
+            else {
+                deferred.notifyWith(this, value);
+                --remaining;
+            }
+        }
+
+        if (!remaining) {
+            deferred.resolveWith(resolveContexts, resolveValues);
+        }
+
+        return deferred.promise();
+    },
+};
+});
diff --git a/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js b/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1843ec8de1a3b59cec8e68279dce9551077e5e0
--- /dev/null
+++ b/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js
@@ -0,0 +1,339 @@
+odoo.define('partner.autocomplete.fieldchar', function (require) {
+'use strict';
+
+var basic_fields = require('web.basic_fields');
+var core = require('web.core');
+var field_registry = require('web.field_registry');
+var Autocomplete = require('partner.autocomplete.core');
+
+var QWeb = core.qweb;
+
+var FieldChar = basic_fields.FieldChar;
+
+/**
+ * FieldChar extension to suggest existing companies when changing the company
+ * name on a res.partner view (indeed, it is designed to change the "name",
+ * "website" and "image" fields of records of this model).
+ */
+var FieldAutocomplete = FieldChar.extend({
+    className: 'o_field_partner_autocomplete',
+    debounceSuggestions: 400,
+    resetOnAnyFieldChange: true,
+
+    jsLibs: [
+        '/partner_autocomplete/static/lib/jsvat.js'
+    ],
+
+    events: _.extend({}, FieldChar.prototype.events, {
+        'keyup': '_onKeyup',
+        'mousedown .o_partner_autocomplete_suggestion': '_onMousedown',
+        'focusout': '_onFocusout',
+        'mouseenter .o_partner_autocomplete_suggestion': '_onHoverDropdown',
+        'click .o_partner_autocomplete_suggestion': '_onSuggestionClicked',
+    }),
+
+    /**
+     * @constructor
+     * Prepares the basic rendering of edit mode by setting the root to be a
+     * div.dropdown.open.
+     * @see FieldChar.init
+     */
+    init: function () {
+        this._super.apply(this, arguments);
+
+        // If the autocomplete is applied to vat field, only search valid vat number
+        this.onlyVAT = this.name === 'vat';
+
+        if (this.mode === 'edit') {
+            this.tagName = 'div';
+            this.className += ' dropdown open';
+        }
+
+        if (this.debounceSuggestions > 0) {
+            this._suggestCompanies = _.debounce(this._suggestCompanies.bind(this), this.debounceSuggestions);
+        }
+    },
+
+    //--------------------------------------------------------------------------
+    // Private
+    //--------------------------------------------------------------------------
+
+    /**
+     * Check if the autocomplete should be active
+     * Active :
+     *  - only when creating new record
+     *  - on model res.partner and is_company=true
+     *  - on model res.company
+     *
+     * @returns {boolean}
+     * @private
+     */
+    _isActive: function () {
+        return this.model === 'res.company' ||
+            (
+                this.model === 'res.partner'
+                && this.record.data.is_company
+                && !(this.record.data && this.record.data.id)
+            );
+    },
+
+    /**
+     *
+     * @private
+     */
+    _removeDropdown: function () {
+        if (this.$dropdown) {
+            this.$dropdown.remove();
+            this.$dropdown = undefined;
+        }
+    },
+
+    /**
+     * Adds the <input/> element and prepares it. Note: the dropdown rendering
+     * is handled outside of the rendering routine (but instead by reacting to
+     * user input).
+     *
+     * @override
+     * @private
+     */
+    _renderEdit: function () {
+        this.$el.empty();
+        // Prepare and add the input
+        this._prepareInput().appendTo(this.$el);
+    },
+
+    /**
+     * Selects the given company suggestions by notifying changes to the view
+     * for the "name", "website" and "image" fields. This is of course intended
+     * to work only with the "res.partner" form view.
+     *
+     * @private
+     * @param {Object} company
+     */
+    _selectCompany: function (company) {
+        var self = this;
+        Autocomplete.getCreateData(company).then(function (data) {
+            if (data.logo) {
+                var logoField = self.model === 'res.partner' ? 'image' : 'logo';
+                data.company[logoField] = data.logo;
+            }
+
+            // Some fields are unnecessary in res.company
+            if (self.model === 'res.company') {
+                var fields = 'comment,child_ids,bank_ids,additional_info'.split(',');
+                fields.forEach(function (field) {
+                    delete data.company[field];
+                });
+            }
+
+            self._setOne2ManyField('child_ids', data.company.child_ids);
+            delete data.company.child_ids;
+
+            self._setOne2ManyField('bank_ids', data.company.bank_ids);
+            delete data.company.bank_ids;
+
+            self.trigger_up('field_changed', {
+                dataPointID: self.dataPointID,
+                changes: data.company,
+            });
+        });
+
+        // update the input's value directly
+        if (this.onlyVAT)
+            this.$input.val(this._formatValue(company.vat));
+        else
+            this.$input.val(this._formatValue(company.name));
+        this._removeDropdown();
+    },
+
+    _setOne2ManyField: function (field, list) {
+        var self = this;
+        var viewType = this.record.viewType;
+        if (list && this.record.fieldsInfo[viewType] && this.record.fieldsInfo[viewType][field]) {
+            list.forEach(function (item) {
+                var changes = {};
+                changes[field] = {
+                    operation: 'CREATE',
+                    data: item,
+                };
+
+                self.trigger_up('field_changed', {
+                    dataPointID: self.dataPointID,
+                    changes: changes,
+                });
+            });
+        }
+    },
+
+    /**
+     * Shows the dropdown with the suggestions. If one is
+     * already opened, it removes the old one before rerendering the dropdown.
+     *
+     * @private
+     */
+    _showDropdown: function () {
+        this._removeDropdown();
+        if (this.suggestions.length > 0) {
+            this.$dropdown = $(QWeb.render('partner_autocomplete.dropdown', {
+                suggestions: this.suggestions,
+            }));
+            this.$dropdown.appendTo(this.$el);
+        }
+    },
+
+    /**
+     * Shows suggestions according to the given value.
+     * Note: this method is debounced (@see init).
+     *
+     * @private
+     * @param {string} value - searched term
+     */
+    _suggestCompanies: function (value) {
+        var self = this;
+        if (Autocomplete.validateSearchTerm(value, this.onlyVAT) && Autocomplete.isOnline()) {
+            return Autocomplete.autocomplete(value).then(function (suggestions) {
+                if (suggestions && suggestions.length) {
+                    self.suggestions = suggestions;
+                    self._showDropdown();
+                } else {
+                    self._removeDropdown();
+                }
+            });
+        } else {
+            this._removeDropdown();
+        }
+    },
+
+
+    //--------------------------------------------------------------------------
+    // Handlers
+    //--------------------------------------------------------------------------
+
+    /**
+     * Called on focusout -> removes the suggestions dropdown.
+     *
+     * @private
+     */
+    _onFocusout: function () {
+        this._removeDropdown();
+    },
+
+    /**
+     * Called when hovering a suggestion in the dropdown -> sets it as active.
+     *
+     * @private
+     * @param {Event} e
+     */
+    _onHoverDropdown: function (e) {
+        this.$dropdown.find('.active').removeClass('active');
+        $(e.currentTarget).parent().addClass('active');
+    },
+
+    /**
+     * @override of FieldChar (called when the user is typing text)
+     * Checks the <input/> value and shows suggestions according to
+     * this value.
+     *
+     * @private
+     */
+    _onInput: function () {
+        this._super.apply(this, arguments);
+        if (this._isActive()) {
+            this._suggestCompanies(this.$input.val());
+        }
+    },
+
+    /**
+     * @override of FieldChar
+     * Changes the "up" and "down" key behavior when the dropdown is opened (to
+     * navigate through dropdown suggestions).
+     * Triggered by keydown to execute the navigation multiple times when the
+     * user keeps the "down" or "up" pressed.
+     *
+     * @private
+     * @param {Event} e
+     */
+    _onKeydown: function (e) {
+        switch (e.which) {
+            case $.ui.keyCode.UP:
+            case $.ui.keyCode.DOWN:
+                if (!this.$dropdown) {
+                    break;
+                }
+                e.preventDefault();
+                var $suggestions = this.$dropdown.children();
+                var $active = $suggestions.filter('.active');
+                var $to;
+                if ($active.length) {
+                    $to = e.which === $.ui.keyCode.DOWN ?
+                        $active.next() :
+                        $active.prev();
+                } else {
+                    $to = $suggestions.first();
+                }
+                if ($to.length) {
+                    $active.removeClass('active');
+                    $to.addClass('active');
+                }
+                return;
+        }
+        this._super.apply(this, arguments);
+    },
+
+    /**
+     * Called on keyup events to:
+     * -> remove the suggestions dropdown when hitting the "escape" key
+     * -> select the highlighted suggestion when hitting the "enter" key
+     *
+     * @private
+     * @param {Event} e
+     */
+    _onKeyup: function (e) {
+        switch (e.which) {
+            case $.ui.keyCode.ESCAPE:
+                e.preventDefault();
+                this._removeDropdown();
+                break;
+            case $.ui.keyCode.ENTER:
+                if (!this.$dropdown) {
+                    break;
+                }
+                e.preventDefault();
+                var $active = this.$dropdown.find('.o_partner_autocomplete_suggestion.active');
+                if (!$active.length) {
+                    return;
+                }
+                this._selectCompany(this.suggestions[$active.data('index')]);
+                break;
+        }
+    },
+
+    /**
+     * Called on mousedown event on a suggestion -> prevent default
+     * action so that the <input/> element does not lose the focus.
+     *
+     * @private
+     * @param {Event} e
+     */
+    _onMousedown: function (e) {
+        e.preventDefault(); // prevent losing focus on suggestion click
+    },
+
+    /**
+     * Called when a dropdown suggestion is clicked -> trigger_up changes for
+     * some fields in the view (not only this <input/> one) with the associated
+     * data (@see _selectCompany).
+     *
+     * @private
+     * @param {Event} e
+     */
+    _onSuggestionClicked: function (e) {
+        e.preventDefault();
+        this._selectCompany(this.suggestions[$(e.currentTarget).data('index')]);
+    },
+});
+
+field_registry.add('field_partner_autocomplete', FieldAutocomplete);
+
+return FieldAutocomplete;
+});
diff --git a/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js b/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js
new file mode 100644
index 0000000000000000000000000000000000000000..40780df75ced9ad1682e90debc241b1444f3f264
--- /dev/null
+++ b/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js
@@ -0,0 +1,138 @@
+odoo.define('partner.autocomplete.many2one', function (require) {
+'use strict';
+
+var FieldMany2One = require('web.relational_fields').FieldMany2One;
+var core = require('web.core');
+var Autocomplete = require('partner.autocomplete.core');
+var field_registry = require('web.field_registry');
+
+var _t = core._t;
+
+var PartnerField = FieldMany2One.extend({
+    jsLibs: [
+        '/partner_autocomplete/static/lib/jsvat.js'
+    ],
+
+    /**
+     * @override
+     */
+    init: function () {
+        this._super.apply(this, arguments);
+        this._addAutocompleteSource(this._searchSuggestions, {
+            placeholder: _t('Searching Autocomplete...'),
+            order: 20,
+            validation: Autocomplete.validateSearchTerm,
+        });
+
+        this.additionalContext['show_vat'] = true;
+    },
+
+    //--------------------------------------------------------------------------
+    // Private
+    //--------------------------------------------------------------------------
+
+    /**
+     * Action : create popup form with pre-filled values from Autocomplete
+     *
+     * @param {Object} company
+     * @returns {Deferred}
+     * @private
+     */
+    _createPartner: function (company) {
+        var self = this;
+        self.$('input').val('');
+
+        return Autocomplete.getCreateData(company).then(function (data){
+            var context = {
+                'default_is_company': true
+            };
+            _.each(data.company, function (val, key) {
+                context['default_' + key] = val && val.id ? val.id : val;
+            });
+
+            // if(data.company.street_name && !data.company.street_number) context.default_street_number = '';
+            if (data.logo) context.default_image = data.logo;
+
+            return self._searchCreatePopup("form", false, context);
+        });
+    },
+
+    /**
+     * Modify autocomplete results rendering
+     * Add logo in the autocomplete results if logo is provided
+     *
+     * @private
+     */
+    _modifyAutompleteRendering: function (){
+        var api = this.$input.data('ui-autocomplete');
+        var renderWithoutLogo = api._renderItem;
+        api._renderItem = function ( ul, item ) {
+            var $li = renderWithoutLogo.call(this, ul, item);
+            if (item.logo){
+                var $a = $li.find('>a').addClass('o_partner_autocomplete_dropdown_item');
+                var $img = $('<img/>').attr('src', item.logo);
+                $a.append($img);
+            }
+
+            return $li;
+        };
+    },
+
+    /**
+     * @override
+     * @private
+     */
+    _renderEdit: function (){
+        this._super.apply(this, arguments);
+        this._modifyAutompleteRendering();
+    },
+
+    /**
+     * Query Autocomplete and add results to the popup
+     *
+     * @override
+     * @param search_val {string}
+     * @returns {Deferred}
+     * @private
+     */
+    _searchSuggestions: function (search_val) {
+        var def = $.Deferred();
+
+        if (Autocomplete.isOnline()) {
+            var self = this;
+
+            Autocomplete.autocomplete(search_val).then(function (suggestions) {
+                var choices = [];
+                if (suggestions && suggestions.length) {
+                    choices.push({
+                        label: _t('Create and Edit from Autocomplete :'),
+                    });
+                    _.each(suggestions, function (suggestion) {
+                        var label =_.str.sprintf('%s - %s', suggestion.label, suggestion.description);
+                        label = label.replace(new RegExp(search_val, "gi"), "<b>$&</b>");
+
+                        choices.push({
+                            label: label,
+                            action: function () {
+                                self._createPartner(suggestion);
+                            },
+                            classname: 'o_m2o_dropdown_option',
+                            logo: suggestion.logo,
+                        });
+                    });
+                }
+
+                def.resolve(choices);
+            });
+        } else {
+            def.resolve([]);
+        }
+
+        return def;
+    },
+});
+
+field_registry.add('res_partner_many2one', PartnerField);
+
+return PartnerField;
+});
diff --git a/addons/partner_autocomplete/static/src/scss/partner_autocomplete.scss b/addons/partner_autocomplete/static/src/scss/partner_autocomplete.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a63e2434b6f33757fdd0b2629230cd871b5362ac
--- /dev/null
+++ b/addons/partner_autocomplete/static/src/scss/partner_autocomplete.scss
@@ -0,0 +1,28 @@
+.o_field_partner_autocomplete.dropdown {
+    display: block;
+
+    > .o_partner_autocomplete_dropdown .dropdown-item {
+        min-width: 300px;
+        padding: 4px 8px;
+        > img {
+            float: left;
+            width: 36px;
+            height: 36px;
+        }
+        > .o_partner_autocomplete_info {
+            margin-left: 50px;
+            > * {
+                @include o-text-overflow(block);
+            }
+        }
+    }
+}
+
+.ui-autocomplete .ui-menu-item > a.o_partner_autocomplete_dropdown_item {
+    > img {
+        float: right;
+        width: 20px;
+        height: 20px;
+    }
+
+}
\ No newline at end of file
diff --git a/addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml b/addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bd6e85c8779ddf1f1226471355a0808ef1c57c88
--- /dev/null
+++ b/addons/partner_autocomplete/static/src/xml/partner_autocomplete.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<templates>
+    <div t-name="partner_autocomplete.dropdown" class="o_partner_autocomplete_dropdown dropdown-menu show" role="menu">
+        <t t-foreach="suggestions" t-as="info">
+            <a role="menuitem" href="#"
+                t-attf-class="dropdown-item o_partner_autocomplete_suggestion clearfix#{info_index == 0 and ' active' or ''}"
+                t-att-data-index="info_index">
+                <img t-att-src="info['logo']" onerror="this.src='/base/static/img/company_image.png'" alt="Placeholder"/>
+                <div class="o_partner_autocomplete_info">
+                    <strong><t t-esc="info['label'] or '&#160;'"/></strong>
+                    <div><t t-esc="info['description']"/></div>
+                </div>
+            </a>
+        </t>
+    </div>
+
+    <div t-name="partner_autocomplete.iap_credit_checker" class="mt-2 row">
+        <div class="col-sm">
+            <div class="loading text-muted">
+                <i class="fa fa-spinner fa-spin"/> Checking remaining credit ...
+            </div>
+            <div class="insufficient">
+                <i class="fa fa-exclamation-triangle text-warning"/> Insufficient credit<br/>
+            </div>
+            <div class="sufficient">
+                <i class="fa fa-check-circle text-success"/> Remaining : <b class="remaining_credits"/> credits
+            </div>
+        </div>
+        <div class="col-sm text-right">
+            <a class="oe_link" target="_blank"><i class="fa fa-arrow-right"/> Buy more credits</a>
+        </div>
+    </div>
+</templates>
diff --git a/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js b/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e7a3ae3c1e854666190acc127038cd7f0a89e84
--- /dev/null
+++ b/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js
@@ -0,0 +1,335 @@
+odoo.define('partner_autocomplete.tests', function (require) {
+    "use strict";
+
+    var FormView = require('web.FormView');
+    var testUtils = require("web.test_utils");
+    var AutocompleteCore = require('partner.autocomplete.core');
+    var AutocompleteField = require('partner.autocomplete.fieldchar');
+
+    var createView = testUtils.createAsyncView;
+
+    function _compareResultFields(assert, form, fields, createData) {
+        var type, formatted, $fieldInput;
+
+        _.each(createData, function (val, key) {
+            if (fields[key]) {
+                if (key === 'image') {
+                    if (val) val = 'data:image/png;base64,' + val;
+                    assert.strictEqual(form.$(".o_field_image img").attr("data-src"), val, 'image value should have been updated to "' + val + '"');
+                } else {
+                    type = fields[key].type;
+                    $fieldInput = form.$('input[name="' + key + '"]');
+                    if ($fieldInput.length) {
+                        formatted = $fieldInput.val();
+                        formatted = type === 'integer' ? parseInt(formatted, 10) : formatted;
+                        assert.strictEqual(
+                            formatted,
+                            val === false ? 0 : val,
+                            key + ' value should have been updated to "' + val + '"'
+                        );
+                    }
+
+                }
+            }
+        });
+    }
+
+    QUnit.module('partner_autocomplete', {
+        before: function () {
+            var suggestions = [
+                {name: "Odoo", website: "odoo.com", logo: "odoo.com/logo.png", vat: "BE0477472701"}
+            ];
+
+            var enrich_data = {
+                country_id: 20,
+                state_id: false,
+                partner_gid: 1,
+                website: "odoo.com",
+                comment: "Comment on Odoo",
+                street: "40 Chaussée de Namur",
+                city: "Ramillies",
+                zip: "1367",
+                phone: "+1 650-691-3277",
+                email: "info@odoo.com",
+                vat: "BE0477472701",
+            };
+
+            testUtils.patch(AutocompleteCore, {
+                _getBase64Image: function (url) {
+                    return $.when(url === "odoo.com/logo.png" ? "odoobase64" : "");
+                },
+                isOnline: function () {
+                    return true;
+                },
+                getCreateData: function (company) {
+                    var self = this;
+                    var def = this._super.apply(this, arguments);
+                    def.then(function (data) {
+                        self._createData = data.company;
+                    });
+                    return def;
+                },
+                enrichCompany: function (company) {
+                    return $.when(enrich_data);
+                },
+                _getOdooSuggestions(value, isVAT) {
+                    var results = _.filter(suggestions, function (suggestion) {
+                        value = value ? value.toLowerCase() : '';
+                        if (isVAT) return (suggestion.vat.toLowerCase().indexOf(value) >= 0);
+                        else return (suggestion.name.toLowerCase().indexOf(value) >= 0);
+                    });
+                    return $.when(results);
+                },
+                _getClearbitSuggestions(value) {
+                    return this._getOdooSuggestions(value);
+                },
+            });
+
+            testUtils.patch(AutocompleteField, {
+                debounceSuggestions: 0,
+            });
+        },
+        beforeEach: function () {
+            this.data = {
+                'res.partner': {
+                    fields: {
+                        company_type: {
+                            string: "Company Type",
+                            type: "selection",
+                            selection: [["company", "Company"], ["individual", "Individual"]],
+                            searchable: true
+                        },
+                        name: {string: "Name", type: "char", searchable: true},
+                        website: {string: "Website", type: "char", searchable: true},
+                        image: {string: "Image", type: "binary", searchable: true},
+                        email: {string: "Email", type: "char", searchable: true},
+                        phone: {string: "Phone", type: "char", searchable: true},
+                        street: {string: "Street", type: "char", searchable: true},
+                        city: {string: "City", type: "char", searchable: true},
+                        zip: {string: "Zip", type: "char", searchable: true},
+                        state_id: {string: "State", type: "integer", searchable: true},
+                        country_id: {string: "Country", type: "integer", searchable: true},
+                        comment: {string: "Comment", type: "char", searchable: true},
+                        vat: {string: "Vat", type: "char", searchable: true},
+                        is_company: {string: "Is comapny", type: "bool", searchable: true},
+                        partner_gid: {string: "Company data ID", type: "integer", searchable: true},
+                    },
+                    records: [],
+                    onchanges: {
+                        company_type: function (obj) {
+                            obj.is_company = obj.company_type === 'company';
+                        },
+                    },
+                },
+            };
+        },
+        after: function () {
+            testUtils.unpatch(AutocompleteField);
+            testUtils.unpatch(AutocompleteCore);
+        },
+    });
+
+    QUnit.test("Partner autocomplete : Company type = Individual", function (assert) {
+        assert.expect(2);
+        var done = assert.async();
+        createView({
+            View: FormView,
+            model: 'res.partner',
+            data: this.data,
+            arch:
+                '<form>' +
+                '<field name="company_type"/>' +
+                '<field name="name" widget="field_partner_autocomplete"/>' +
+                '<field name="website"/>' +
+                '<field name="image" widget="image"/>' +
+                '</form>',
+        }).then(function (form){
+            // Set company type to Individual
+            var $company_type = form.$("select[name='company_type']");
+            $company_type.val('"individual"').trigger('change');
+
+            // Check input exists
+            var $input = form.$(".o_field_partner_autocomplete > input:visible");
+            assert.strictEqual($input.length, 1, "there should be an <input/> for the Partner field");
+
+            // Change input val and assert nothing happens
+            $input.val("odoo").trigger("input");
+            var $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 0, "there should not be an opened dropdown");
+
+            form.destroy();
+
+            done();
+        });
+    });
+
+
+    QUnit.test("Partner autocomplete : Company type = Company / Name search", function (assert) {
+        assert.expect(21);
+        var done = assert.async();
+        var fields = this.data['res.partner'].fields;
+        createView({
+            View: FormView,
+            model: 'res.partner',
+            data: this.data,
+            arch:
+                '<form>' +
+                '<field name="company_type"/>' +
+                '<field name="name" widget="field_partner_autocomplete"/>' +
+                '<field name="website"/>' +
+                '<field name="image" widget="image"/>' +
+                '<field name="email"/>' +
+                '<field name="phone"/>' +
+                '<field name="street"/>' +
+                '<field name="city"/>' +
+                '<field name="state_id"/>' +
+                '<field name="zip"/>' +
+                '<field name="country_id"/>' +
+                '<field name="comment"/>' +
+                '<field name="vat"/>' +
+                '</form>',
+            mockRPC: function (route, args) {
+                if (args.method) {
+                    assert.step(args.method);
+                }
+                if (route === "/web/static/src/img/placeholder.png"
+                    || route === "odoo.com/logo.png"
+                    || route === "data:image/png;base64,odoobase64") { // land here as it is not valid base64 content
+                    return $.when();
+                }
+                return this._super.apply(this, arguments);
+            },
+        }).then(function (form){
+            // Set company type to Company
+            var $company_type = form.$("select[name='company_type']");
+            $company_type.val('"company"').trigger('change');
+
+            // Check input exists
+            var $input = form.$(".o_field_partner_autocomplete > input:visible");
+            assert.strictEqual($input.length, 1, "there should be an <input/> for the field");
+
+            // Change input val and assert changes
+            $input.val("odoo").trigger("input");
+
+            var $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown");
+            assert.strictEqual($dropdown.children().length, 1, "there should be only one proposition");
+
+            $dropdown.find("a").first().click();
+            $input = form.$(".o_field_partner_autocomplete > input");
+            assert.strictEqual($input.val(), "Odoo", "Input value should have been updated to \"Odoo\"");
+            assert.strictEqual(form.$("input.o_field_widget").val(), "odoo.com", "website value should have been updated to \"odoo.com\"");
+
+            _compareResultFields(assert, form, fields, AutocompleteCore._createData);
+
+            // Try suggestion with bullshit query
+            $input.val("ZZZZZZZZZZZZZZZZZZZZZZ").trigger("input");
+            $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 0, "there should be no opened dropdown when no result");
+
+            // Try autocomplete again
+            $input.val("odoo").trigger("input");
+            $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown when typing odoo letters again");
+
+            // Test if dropdown closes on focusout
+            $input.trigger("focusout");
+            $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 0, "unfocusing the input should close the dropdown");
+
+            form.destroy();
+
+            done();
+        });
+    });
+
+    QUnit.test("Partner autocomplete : Company type = Company / VAT search", function (assert) {
+        assert.expect(32);
+        var done = assert.async();
+        var fields = this.data['res.partner'].fields;
+        createView({
+            View: FormView,
+            model: 'res.partner',
+            data: this.data,
+            arch:
+                '<form>' +
+                '<field name="company_type"/>' +
+                '<field name="name" widget="field_partner_autocomplete"/>' +
+                '<field name="website"/>' +
+                '<field name="image" widget="image"/>' +
+                '<field name="email"/>' +
+                '<field name="phone"/>' +
+                '<field name="street"/>' +
+                '<field name="city"/>' +
+                '<field name="state_id"/>' +
+                '<field name="zip"/>' +
+                '<field name="country_id"/>' +
+                '<field name="comment"/>' +
+                '<field name="vat"/>' +
+                '</form>',
+            mockRPC: function (route, args) {
+                if (args.method) {
+                    assert.step(args.method);
+                }
+                if (route === "/web/static/src/img/placeholder.png"
+                    || route === "odoo.com/logo.png"
+                    || route === "data:image/png;base64,odoobase64") { // land here as it is not valid base64 content
+                    return $.when();
+                }
+                return this._super.apply(this, arguments);
+            },
+        }).then(function (form){
+            // Set company type to Company
+            var $company_type = form.$("select[name='company_type']");
+            $company_type.val('"company"').trigger('change');
+
+
+            // Check input exists
+            var $input = form.$(".o_field_partner_autocomplete > input:visible");
+            assert.strictEqual($input.length, 1, "there should be an <input/> for the field");
+
+            // Set incomplete VAT and assert changes
+            $input.val("BE047747270").trigger("input");
+
+            var $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 0, "there should be no opened dropdown no results with incomplete VAT number");
+
+            // Set complete VAT and assert changes
+            // First suggestion (only vat result)
+            $input.val("BE0477472701").trigger("input");
+            $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown");
+            assert.strictEqual($dropdown.children().length, 1, "there should be one proposition for complete VAT number");
+
+            $dropdown.find("a").first().click();
+
+            $input = form.$(".o_field_partner_autocomplete > input");
+            assert.strictEqual($input.val(), "Odoo", "Input value should have been updated to \"Odoo\"");
+
+            _compareResultFields(assert, form, fields, AutocompleteCore._createData);
+
+            // Set complete VAT and assert changes
+            // Second suggestion (only vat + clearbit result)
+            $input.val("BE0477472701").trigger("input");
+            $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown");
+            assert.strictEqual($dropdown.children().length, 1, "there should be one proposition for complete VAT number");
+
+            $dropdown.find("a").first().click();
+
+            $input = form.$(".o_field_partner_autocomplete > input");
+            assert.strictEqual($input.val(), "Odoo", "Input value should have been updated to \"Odoo\"");
+
+            _compareResultFields(assert, form, fields, AutocompleteCore._createData);
+
+            // Test if dropdown closes on focusout
+            $input.trigger("focusout");
+            $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible");
+            assert.strictEqual($dropdown.length, 0, "unfocusing the input should close the dropdown");
+
+            form.destroy();
+
+            done();
+        });
+    });
+});
\ No newline at end of file
diff --git a/addons/partner_autocomplete/views/additional_info_template.xml b/addons/partner_autocomplete/views/additional_info_template.xml
new file mode 100644
index 0000000000000000000000000000000000000000..70290f59af0caeaaf1f0bf1fd4804215d958e00f
--- /dev/null
+++ b/addons/partner_autocomplete/views/additional_info_template.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <template id="additional_info_template">
+        <p t-if="description">
+            <b>Description</b><br/>
+            <t t-esc="description"/><br/>
+        </p>
+        <p>
+            <t t-if="employees">
+                <b>Employees:</b> <t t-esc="employees"/><br/>
+            </t>
+            <t t-if="annual_revenue">
+                <b>Annual revenue:</b> <t t-esc="annual_revenue"/><br/>
+            </t>
+            <t t-if="estimated_annual_revenue">
+                <b>Estimated annual revenue:</b> <t t-esc="estimated_annual_revenue"/><br/>
+            </t>
+            <t t-if="sector">
+                <b>Sector:</b> <t t-esc="sector"/><br/>
+            </t>
+            <t t-if="tech">
+                <b>Tech:</b> <t t-esc="tech"/><br/>
+            </t>
+        </p>
+        <p>
+            <b>Social networks</b><br/>
+            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Facebook:</b> <a t-att-href="facebook" target="_blank"><t t-esc="facebook"/></a><br/>
+            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Linkedin:</b> <a t-att-href="linkedin" target="_blank"><t t-esc="linkedin"/></a><br/>
+            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Crunchbase:</b> <a t-att-href="crunchbase" target="_blank"><t t-esc="crunchbase"/></a><br/>
+            &amp;nbsp;&amp;nbsp;&amp;nbsp; <b>Twitter:</b> <a t-att-href="twitter" target="_blank"><t t-esc="twitter"/></a><br/>
+        </p>
+        <p t-if="emails">
+            <b>Email addresses</b><br/>
+            <t t-foreach="emails" t-as="email">
+                &amp;nbsp;&amp;nbsp;&amp;nbsp; <a t-att-href="'mailto:%s' % email"><t t-esc="email"/></a><br/>
+            </t>
+        </p>
+        <p t-if="phones">
+            <b>Phone numbers</b><br/>
+            <t t-foreach="phones" t-as="phone">
+                &amp;nbsp;&amp;nbsp;&amp;nbsp; <t t-esc="phone"/><br/>
+            </t>
+        </p>
+    </template>
+</odoo>
diff --git a/addons/partner_autocomplete/views/partner_autocomplete_assets.xml b/addons/partner_autocomplete/views/partner_autocomplete_assets.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8e9f1ecb300c84c55bf61334450f311370a56182
--- /dev/null
+++ b/addons/partner_autocomplete/views/partner_autocomplete_assets.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <template id="assets_backend" name="Partner Autocomplete Assets" inherit_id="web.assets_backend">
+        <xpath expr="." position="inside">
+            <link rel="stylesheet" type="text/scss" href="/partner_autocomplete/static/src/scss/partner_autocomplete.scss"/>
+            <script type="text/javascript" src="/partner_autocomplete/static/src/js/partner_autocomplete_core.js" />
+            <script type="text/javascript" src="/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js" />
+            <script type="text/javascript" src="/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js" />
+            <script type="text/javascript" src="/partner_autocomplete/static/src/js/iap_credit_checker_widget.js" />
+        </xpath>
+    </template>
+
+    <template id="qunit_suite" inherit_id="web.qunit_suite">
+        <xpath expr="//script[last()]" position="after">
+            <script type="text/javascript" src="/partner_autocomplete/static/tests/partner_autocomplete_tests.js"/>
+        </xpath>
+    </template>
+</odoo>
diff --git a/addons/partner_autocomplete/views/res_company_views.xml b/addons/partner_autocomplete/views/res_company_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..64fdfe85809a5d871872288e4c3dbebad3448431
--- /dev/null
+++ b/addons/partner_autocomplete/views/res_company_views.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <record id="view_company_form_inherit_partner_autocomplete" model="ir.ui.view">
+        <field name="name">res.company.form.inherit.web.partner.autocomplete</field>
+        <field name="model">res.company</field>
+        <field name="inherit_id" ref="base.view_company_form"/>
+        <field name="arch" type="xml">
+            <xpath expr="//div[hasclass('oe_title')]/h1/field[@name='name']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[@name='vat']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[last()]" position="after">
+                <field name="partner_gid" invisible="True"/>
+            </xpath>
+        </field>
+    </record>
+</odoo>
diff --git a/addons/partner_autocomplete/views/res_config_settings_views.xml b/addons/partner_autocomplete/views/res_config_settings_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8c97b9e4aeb3ddbf63944d0f184586fe7d500319
--- /dev/null
+++ b/addons/partner_autocomplete/views/res_config_settings_views.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <record id="res_config_settings_view_form" model="ir.ui.view">
+        <field name="name">res.config.settings.view.form.inherit.partner.autcomplete</field>
+        <field name="model">res.config.settings</field>
+        <field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
+        <field name="arch" type="xml">
+            <div id="partner_autocomplete_settings" position="inside">
+                <widget name="iap_credit_checker" service_name="partner_autocomplete"/>
+            </div>
+
+            <xpath expr="//div[hasclass('app_settings_block')]" position="before">
+                <field name="partner_autocomplete_insufficient_credit" invisible="1"/>
+                <div class="alert alert-info alert-dismissible fade show pt-2 pb-2" role="alert" attrs="{'invisible': [('partner_autocomplete_insufficient_credit', '=', False)]}">
+                    <i class="fa fa-exclamation-triangle text-warning"></i> &amp;nbsp; You don't have credits to auto-complete companies' data anymore.
+                    <button name="redirect_to_buy_autocmplete_credit" type="object" class="btn-link">
+                        <i class="fa fa-arrow-right"/>
+                        Buy more credits
+                    </button>
+                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                        <span>&amp;times;</span>
+                    </button>
+                </div>
+            </xpath>
+        </field>
+    </record>
+</odoo>
+
diff --git a/addons/partner_autocomplete/views/res_partner_views.xml b/addons/partner_autocomplete/views/res_partner_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d7234bb3774fc51fd60260f3a30ccb55c8a1ff4e
--- /dev/null
+++ b/addons/partner_autocomplete/views/res_partner_views.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <record id="view_res_partner_form_inherit_partner_autocomplete" model="ir.ui.view">
+        <field name="name">res.partner.form.inherit.partner.autocomplete</field>
+        <field name="model">res.partner</field>
+        <field name="inherit_id" ref="base.view_partner_form"/>
+        <field name="arch" type="xml">
+            <xpath expr="//div[hasclass('oe_title')]/h1/field[@name='name']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[@name='vat']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[last()]" position="after">
+                <field name="partner_gid" invisible="True"/>
+                <field name="additional_info" invisible="True"/>
+            </xpath>
+            <xpath expr="//div[hasclass('oe_title')]/div[hasclass('o_row')]/field[@name='parent_id']" position="attributes">
+                <attribute name="help">You can find a customer, a contact, etc. by its Name, TIN, Email or Internal Reference.</attribute>
+            </xpath>
+        </field>
+    </record>
+
+    <record id="view_res_partner_short_form_inherit_partner_autocomplete" model="ir.ui.view">
+        <field name="name">res.partner.short.form.inherit.partner.autocomplete</field>
+        <field name="model">res.partner</field>
+        <field name="inherit_id" ref="base.view_partner_short_form"/>
+        <field name="arch" type="xml">
+            <xpath expr="//div[hasclass('oe_title')]/h1/field[@name='name']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[@name='vat']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[last()]" position="after">
+                <field name="partner_gid" invisible="True"/>
+                <field name="additional_info" invisible="True"/>
+            </xpath>
+            <xpath expr="//div[hasclass('oe_title')]/div[hasclass('o_row')]/field[@name='parent_id']" position="attributes">
+                <attribute name="help">You can find a customer, a contact, etc. by its Name, TIN, Email or Internal Reference.</attribute>
+            </xpath>
+        </field>
+    </record>
+
+    <record id="view_partner_simple_form_inherit_partner_autocomplete" model="ir.ui.view">
+        <field name="name">res.partner.simplified.form.inherit.partner.autocomplete</field>
+        <field name="model">res.partner</field>
+        <field name="inherit_id" ref="base.view_partner_simple_form"/>
+        <field name="arch" type="xml">
+            <xpath expr="//div[hasclass('oe_title')]/h1/field[@name='name']" position="attributes">
+                <attribute name="widget">field_partner_autocomplete</attribute>
+            </xpath>
+            <xpath expr="//field[last()]" position="after">
+                <field name="partner_gid" invisible="True"/>
+                <field name="additional_info" invisible="True"/>
+            </xpath>
+        </field>
+    </record>
+</odoo>
diff --git a/addons/partner_autocomplete_address_extended/__init__.py b/addons/partner_autocomplete_address_extended/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..cde864bae21a11c0e4f50067aa46b4c497549b4c
--- /dev/null
+++ b/addons/partner_autocomplete_address_extended/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from . import models
diff --git a/addons/partner_autocomplete_address_extended/__manifest__.py b/addons/partner_autocomplete_address_extended/__manifest__.py
new file mode 100644
index 0000000000000000000000000000000000000000..85a86f231e12263e579223d81de16a73cbb49e06
--- /dev/null
+++ b/addons/partner_autocomplete_address_extended/__manifest__.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "Partner Autocomplete extends Address autocomplete",
+    'summary': """
+        Correct address formating when both modules are installed""",
+    'author': "Odoo SA",
+    'category': 'Tools',
+    'version': '1.0',
+    'depends': ['partner_autocomplete', 'base_address_extended'],
+    'auto_install': True,
+}
diff --git a/addons/partner_autocomplete_address_extended/models/__init__.py b/addons/partner_autocomplete_address_extended/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b86ffb924b34e9b1d4cd4486e469fa00d2d544c
--- /dev/null
+++ b/addons/partner_autocomplete_address_extended/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import res_partner
\ No newline at end of file
diff --git a/addons/partner_autocomplete_address_extended/models/res_partner.py b/addons/partner_autocomplete_address_extended/models/res_partner.py
new file mode 100644
index 0000000000000000000000000000000000000000..79c604eed7a9b3c816248a42be82db10afb34f15
--- /dev/null
+++ b/addons/partner_autocomplete_address_extended/models/res_partner.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import re
+from odoo import api, fields, models
+
+
+class ResPartner(models.Model):
+    _name = 'res.partner'
+    _inherit = 'res.partner'
+
+    @api.model
+    def _split_street_with_params(self, street_raw, street_format=False):
+        regex = '((\d+\w* ?(-|\/) ?\d*\w*)|(\d+\w*))'
+
+        street_name = street_raw
+        street_number = ''
+        street_number2 = ''
+
+        # Try to find number at beginning
+        start_regex = re.compile('^' + regex)
+        matches = re.search(start_regex, street_raw)
+        if matches and matches.group(0):
+            street_number = matches.group(0)
+            street_name = re.sub(start_regex, '', street_raw, 1)
+        else:
+            # Try to find number at end
+            end_regex = re.compile(regex + '$')
+            matches = re.search(end_regex, street_raw)
+            if matches and matches.group(0):
+                street_number = matches.group(0)
+                street_name = re.sub(end_regex, '', street_raw, 1)
+
+        if street_number:
+            street_number_split = street_number.split('/')
+            if len(street_number_split) > 1:
+                street_number2 = street_number_split.pop(-1)
+                street_number = '/'.join(street_number_split)
+
+        return {
+            'street_name': street_name.strip(),
+            'street_number': street_number.strip(),
+            'street_number2': street_number2.strip(),
+        }
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 8e8ae8c77b672f0eb5170a040131dee8e9d3d687..90ac6e930f121944eb0a77690daef6449be987a9 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -85,7 +85,7 @@ class PurchaseOrder(models.Model):
     date_order = fields.Datetime('Order Date', required=True, states=READONLY_STATES, index=True, copy=False, default=fields.Datetime.now,\
         help="Depicts the date where the Quotation should be validated and converted into a purchase order.")
     date_approve = fields.Date('Approval Date', readonly=1, index=True, copy=False)
-    partner_id = fields.Many2one('res.partner', string='Vendor', required=True, states=READONLY_STATES, change_default=True, track_visibility='always')
+    partner_id = fields.Many2one('res.partner', string='Vendor', required=True, states=READONLY_STATES, change_default=True, track_visibility='always', help="You can find a vendor by its Name, TIN, Email or Internal Reference.")
     dest_address_id = fields.Many2one('res.partner', string='Drop Ship Address', states=READONLY_STATES,
         help="Put an address if you want to deliver directly from the vendor to the customer. "
              "Otherwise, keep empty to deliver to your own company.")
diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml
index aa4cf40bb15cbaaac709c861c2039ceeb92be0d6..437d86a0c75a434cbb065ef4b73c636910a0f82e 100644
--- a/addons/purchase/views/purchase_views.xml
+++ b/addons/purchase/views/purchase_views.xml
@@ -165,7 +165,9 @@
                     </div>
                     <group>
                         <group>
-                            <field name="partner_id" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0}" domain="[('supplier','=',True)]"/>
+                            <field name="partner_id" widget="res_partner_many2one" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0, 'show_vat': True}" domain="[('supplier','=',True)]"
+                                placeholder="Name, TIN, Email, or Reference"
+                            />
                             <field name="partner_ref"/>
                             <field name="currency_id" groups="base.group_multi_currency"/>
                         </group>
diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py
index e38c76e20ce45302b85d1d9edb27c1083ec6dbf0..1302cb93a01cbde48c65c0841ac4db396c5b452e 100644
--- a/addons/repair/models/repair.py
+++ b/addons/repair/models/repair.py
@@ -46,7 +46,7 @@ class Repair(models.Model):
     partner_id = fields.Many2one(
         'res.partner', 'Customer',
         index=True, states={'confirmed': [('readonly', True)]},
-        help='Choose partner for whom the order will be invoiced and delivered.')
+        help='Choose partner for whom the order will be invoiced and delivered. You can find a partner by its Name, TIN, Email or Internal Reference.')
     address_id = fields.Many2one(
         'res.partner', 'Delivery Address',
         domain="[('parent_id','=',partner_id)]",
diff --git a/addons/repair/views/repair_views.xml b/addons/repair/views/repair_views.xml
index 005dca2936cedf06a0d6219bbe2d6798b947ea27..ca2f0fd5aec98eb8e6c7bad7769dec472e856476 100644
--- a/addons/repair/views/repair_views.xml
+++ b/addons/repair/views/repair_views.xml
@@ -59,7 +59,7 @@
                                 <field name="product_uom" groups="uom.group_uom"/>
                             </div>
                             <field name="lot_id" domain="[('product_id', '=', product_id)]" context="{'default_product_id': product_id}" groups="stock.group_production_lot" attrs="{'required': [('tracking', '!=', 'none')], 'readonly': [('state', '=', 'done')]}"/>
-                            <field name="partner_id" attrs="{'required':[('invoice_method','!=','none')]}"/>
+                            <field name="partner_id" widget="res_partner_many2one" attrs="{'required':[('invoice_method','!=','none')]}" context="{'show_vat': True}"/>
                             <field name="address_id" groups="sale.group_delivery_invoice_address"/>
                         </group>
                         <group>
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 8547a0cf5db85ad39033fac53baa0fc6db3715be..aa317ebff59dfbd0606bd90e4dc39dd0f5568d3e 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -154,7 +154,7 @@ class SaleOrder(models.Model):
     create_date = fields.Datetime(string='Creation Date', readonly=True, index=True, help="Date on which sales order is created.")
     confirmation_date = fields.Datetime(string='Confirmation Date', readonly=True, index=True, help="Date on which the sales order is confirmed.", oldname="date_confirm", copy=False)
     user_id = fields.Many2one('res.users', string='Salesperson', index=True, track_visibility='onchange', track_sequence=2, default=lambda self: self.env.user)
-    partner_id = fields.Many2one('res.partner', string='Customer', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, required=True, change_default=True, index=True, track_visibility='always', track_sequence=1)
+    partner_id = fields.Many2one('res.partner', string='Customer', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, required=True, change_default=True, index=True, track_visibility='always', track_sequence=1, help="You can find a customer by its Name, TIN, Email or Internal Reference.")
     partner_invoice_id = fields.Many2one('res.partner', string='Invoice Address', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]}, help="Invoice address for current sales order.")
     partner_shipping_id = fields.Many2one('res.partner', string='Delivery Address', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]}, help="Delivery address for current sales order.")
 
diff --git a/addons/sale/views/sale_views.xml b/addons/sale/views/sale_views.xml
index 4125995230715897245008b8deec13993b784335..21876534f7ed3b012634a78970b5dbe58aab09fa 100644
--- a/addons/sale/views/sale_views.xml
+++ b/addons/sale/views/sale_views.xml
@@ -264,7 +264,7 @@
                     </div>
                     <group>
                         <group>
-                            <field name="partner_id" domain="[('customer','=',True)]" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
+                            <field name="partner_id" widget="res_partner_many2one" domain="[('customer','=',True)]" context="{'search_default_customer':1, 'show_address': 1, 'show_vat': True}" options='{"always_reload": True}'/>
                             <field name="partner_invoice_id" groups="sale.group_delivery_invoice_address" context="{'default_type':'invoice'}" options='{"always_reload": True}'/>
                             <field name="partner_shipping_id" groups="sale.group_delivery_invoice_address" context="{'default_type':'delivery'}" options='{"always_reload": True}'/>
                         </group>
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index a1efa85498e5f269425d77153be2ce1b7ad06203..c3d25f37d0929b05e3100100fbb9db77c2117150 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -138,6 +138,11 @@ var FieldMany2One = AbstractField.extend({
         this.isDirty = false;
         this.lastChangeEvent = undefined;
 
+        // List of autocomplete sources
+        this._autocompleteSources = [];
+        // Add default search method for M20 (name_search)
+        this._addAutocompleteSource(this._search, {placeholder: _t('Loading...'), order: 1});
+
         // use a DropPrevious to properly handle related record quick creations,
         // and store a createDef to be able to notify the environment that there
         // is pending quick create operation
@@ -212,6 +217,24 @@ var FieldMany2One = AbstractField.extend({
     // Private
     //--------------------------------------------------------------------------
 
+    /**
+     * Add a source to the autocomplete results
+     *
+     * @param {function} method : A function that returns a list of results. If async source, the function should return a promise
+     * @param {Object} params : Parameters containing placeholder/validation/order
+     * @private
+     */
+    _addAutocompleteSource: function (method, params) {
+        this._autocompleteSources.push({
+            method: method,
+            placeholder: (params.placeholder ? _t(params.placeholder) : _t('Loading...')) + '<i class="fa fa-spinner fa-spin pull-right"></i>' ,
+            validation: params.validation,
+            loading: false,
+            order: params.order || 999
+        });
+
+        this._autocompleteSources = _.sortBy(this._autocompleteSources, 'order');
+    },
     /**
      * @private
      */
@@ -219,8 +242,22 @@ var FieldMany2One = AbstractField.extend({
         var self = this;
         this.$input.autocomplete({
             source: function (req, resp) {
-                self._search(req.term).then(function (result) {
-                    resp(result);
+                _.each(self._autocompleteSources, function (source) {
+                    // Resets the results for this source
+                    source.results = [];
+
+                    // Check if this source should be used for the searched term
+                    if (!source.validation || source.validation.call(self, req.term)) {
+                        source.loading = true;
+
+                        // Wrap the returned value of the source.method with $.when.
+                        // So event if the returned value is not async, it will work
+                        $.when(source.method.call(self, req.term)).then(function (results) {
+                            source.results = results;
+                            source.loading = false;
+                            resp(self._concatenateAutocompleteResults());
+                        });
+                    }
                 });
             },
             select: function (event, ui) {
@@ -256,6 +293,25 @@ var FieldMany2One = AbstractField.extend({
         this.$input.autocomplete("option", "position", { my : "left top", at: "left bottom" });
         this.autocomplete_bound = true;
     },
+    /**
+     * Concatenate async results for autocomplete.
+     *
+     * @returns {Array}
+     * @private
+     */
+    _concatenateAutocompleteResults: function () {
+        var results = [];
+        _.each(this._autocompleteSources, function (source) {
+            if (source.results && source.results.length) {
+                results = results.concat(source.results);
+            } else if (source.loading) {
+                results.push({
+                    label: source.placeholder
+                });
+            }
+        });
+        return results;
+    },
     /**
      * @private
      * @param {string} [name]
@@ -389,6 +445,8 @@ var FieldMany2One = AbstractField.extend({
         this.m2o_value = this._formatValue(this.value);
     },
     /**
+     * Executes a name_search and process its result.
+     *
      * @private
      * @param {string} search_val
      * @returns {Deferred}
diff --git a/addons/web/static/src/js/fields/upgrade_fields.js b/addons/web/static/src/js/fields/upgrade_fields.js
index dd91ca2efc2a1f5fb82ba72416e7c346e373d219..445cc18cf8191224fa8dcd91633ab911166daa85 100644
--- a/addons/web/static/src/js/fields/upgrade_fields.js
+++ b/addons/web/static/src/js/fields/upgrade_fields.js
@@ -146,6 +146,7 @@ var UpgradeBoolean = FieldBoolean.extend(AbstractFieldUpgrade, {
      * @private
      */
     _insertEnterpriseLabel: function ($enterpriseLabel) {
+        if(this.name==='module_partner_autocomplete') debugger;
         var $el = this.$label || this.$el;
         $el.append('&nbsp;').append($enterpriseLabel);
     },
diff --git a/odoo/addons/base/models/res_partner.py b/odoo/addons/base/models/res_partner.py
index c74e10f28cb35e89ce4db5577d93ae138c91097f..916bf15d731543ffab747ac439a634efb138833a 100644
--- a/odoo/addons/base/models/res_partner.py
+++ b/odoo/addons/base/models/res_partner.py
@@ -6,6 +6,7 @@ import datetime
 import hashlib
 import pytz
 import threading
+import re
 
 from email.utils import formataddr
 
@@ -239,6 +240,12 @@ class Partner(models.Model):
         ('check_name', "CHECK( (type='contact' AND name IS NOT NULL) or (type!='contact') )", 'Contacts require a name.'),
     ]
 
+    @api.model_cr
+    def init(self):
+        self._cr.execute("""SELECT indexname FROM pg_indexes WHERE indexname = 'res_partner_vat_index'""")
+        if not self._cr.fetchone():
+            self._cr.execute("""CREATE INDEX res_partner_vat_index ON res_partner (regexp_replace(upper(vat), '[^A-Z0-9]+', '', 'g'))""")
+
     @api.depends('is_company', 'name', 'parent_id.name', 'type', 'company_name')
     def _compute_display_name(self):
         diff = dict(show_address=None, show_address_only=None, show_email=None)
@@ -610,6 +617,8 @@ class Partner(models.Model):
             name = "%s <%s>" % (name, partner.email)
         if self._context.get('html_format'):
             name = name.replace('\n', '<br/>')
+        if self._context.get('show_vat') and partner.vat:
+            name = "%s - %s" % (name, partner.vat)
         return name
 
     @api.multi
@@ -697,7 +706,9 @@ class Partner(models.Model):
                                percent=unaccent('%s'),
                                vat=unaccent('vat'),)
 
-            where_clause_params += [search_name]*5
+            where_clause_params += [search_name]*3  # for email / display_name, reference
+            where_clause_params += [re.sub('[^a-zA-Z0-9]+', '', search_name)]  # for vat
+            where_clause_params += [search_name]  # for order by
             if limit:
                 query += ' limit %s'
                 where_clause_params.append(limit)
diff --git a/odoo/addons/base/views/res_bank_views.xml b/odoo/addons/base/views/res_bank_views.xml
index 1df3b1cfa58e08d872f0bb6daf1f262b97da6526..c053a1e7b26fcba81eae1a0fdc86b9e71afe6783 100644
--- a/odoo/addons/base/views/res_bank_views.xml
+++ b/odoo/addons/base/views/res_bank_views.xml
@@ -88,6 +88,7 @@
                     <field name="bank_name"/>
                     <field name="company_id" groups="base.group_multi_company"/>
                     <field name="partner_id"/>
+                    <field name="acc_holder_name" invisible="1"/>
                 </tree>
             </field>
         </record>
diff --git a/odoo/addons/base/views/res_partner_views.xml b/odoo/addons/base/views/res_partner_views.xml
index 4f9905858b3b61bd3dae6e5ac7a79e7f0f02a50b..a6ba287dcff613a897074315904f6c7860f92ae1 100644
--- a/odoo/addons/base/views/res_partner_views.xml
+++ b/odoo/addons/base/views/res_partner_views.xml
@@ -70,8 +70,9 @@
                             <field name="name" default_focus="1" placeholder="Name" attrs="{'required' : [('type', '=', 'contact')]}"/>
                         </h1>
                         <field name="parent_id"
+                            widget="res_partner_many2one"
                             placeholder="Company"
-                            domain="[('is_company', '=', True)]" context="{'default_is_company': True}"
+                            domain="[('is_company', '=', True)]" context="{'default_is_company': True, 'show_vat': True}"
                             attrs="{'invisible': [('is_company','=', True)]}"/>
                     </div>
                     <group>
@@ -142,8 +143,9 @@
                         </h1>
                         <div class="o_row">
                             <field name="parent_id"
+                                widget="res_partner_many2one"
                                 placeholder="Company"
-                                domain="[('is_company', '=', True)]" context="{'default_is_company': True, 'default_supplier': supplier, 'default_customer': customer}"
+                                domain="[('is_company', '=', True)]" context="{'default_is_company': True, 'default_supplier': supplier, 'default_customer': customer, 'show_vat': True}"
                                 attrs="{'invisible': ['|', '&amp;', ('is_company','=', True),('parent_id', '=', False),('company_name', '!=', False),('company_name', '!=', '')]}"/>
                                 <field name="company_name" attrs="{'invisible': ['|', '|', ('company_name', '=', False), ('company_name', '=', ''), ('is_company', '=', True)]}"/>
                                 <button name="create_company" type="object" class="oe_edit_only btn-link"
@@ -215,8 +217,9 @@
                         </h1>
                         <div class="o_row">
                             <field name="parent_id"
+                                widget="res_partner_many2one"
                                 placeholder="Company"
-                                domain="[('is_company', '=', True)]" context="{'default_is_company': True, 'default_supplier': supplier, 'default_customer': customer}"
+                                domain="[('is_company', '=', True)]" context="{'default_is_company': True, 'default_supplier': supplier, 'default_customer': customer, 'show_vat': True}"
                                 attrs="{'invisible': ['|', '&amp;', ('is_company','=', True),('parent_id', '=', False),('company_name', '!=', False),('company_name', '!=', '')]}"/>
                                 <field name="company_name" attrs="{'invisible': ['|', '|', ('company_name', '=', False), ('company_name', '=', ''), ('is_company', '=', True)]}"/>
                                 <button name="create_company" type="object" class="oe_edit_only btn-link"
@@ -429,6 +432,7 @@
                             <field name="bank_ids">
                                 <tree editable="bottom">
                                     <field name="acc_number"/>
+                                    <field name="acc_holder_name" invisible="1"/>
                                 </tree>
                             </field>
                         </group>
@@ -585,7 +589,7 @@
             <field name="view_type">form</field>
             <field name="view_mode">kanban,tree,form</field>
             <field name="domain">[]</field>
-            <field name="context">{'default_customer':1, 'search_default_customer':1, 'default_company_type': 'company','default_is_company': 1}</field>
+            <field name="context">{'default_customer':1, 'search_default_customer':1, 'default_is_company': True}</field>
             <field name="filter" eval="True"/>
             <field name="help" type="html">
               <p class="o_view_nocontent_smiling_face">
@@ -621,7 +625,7 @@
             <field name="view_type">form</field>
             <field name="domain">[]</field>
             <field name="view_mode">kanban,tree,form</field>
-            <field name="context">{'search_default_supplier': 1,'default_customer': 0,'default_supplier': 1, 'default_company_type': 'company'}</field>
+            <field name="context">{'search_default_supplier': 1,'default_customer': 0,'default_supplier': 1, 'default_is_company': True}</field>
             <field name="filter" eval="True"/>
             <field name="help" type="html">
               <p class="o_view_nocontent_smiling_face">