diff --git a/addons/odoo_referral/__init__.py b/addons/odoo_referral/__init__.py
new file mode 100644
index 00000000000..bb0aae7ee63
--- /dev/null
+++ b/addons/odoo_referral/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from . import controllers
+from . import models
diff --git a/addons/odoo_referral/__manifest__.py b/addons/odoo_referral/__manifest__.py
new file mode 100644
index 00000000000..7b1a47bb876
--- /dev/null
+++ b/addons/odoo_referral/__manifest__.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+{
+ 'name': "Odoo referral program",
+ 'summary': """Allow you to refer your friends to Odoo and get rewards""",
+ 'category': 'Hidden',
+ 'version': '1.0',
+ 'depends': ['base', 'web'],
+ 'data': [
+ 'views/templates.xml',
+ ],
+ 'qweb': [
+ "static/src/xml/systray.xml",
+ ],
+ 'auto_install': True,
+}
diff --git a/addons/odoo_referral/controllers/__init__.py b/addons/odoo_referral/controllers/__init__.py
new file mode 100644
index 00000000000..5e307cd5a18
--- /dev/null
+++ b/addons/odoo_referral/controllers/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import referral
diff --git a/addons/odoo_referral/controllers/referral.py b/addons/odoo_referral/controllers/referral.py
new file mode 100644
index 00000000000..7364d500b1e
--- /dev/null
+++ b/addons/odoo_referral/controllers/referral.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.http import Controller, request, route
+
+
+class Referral(Controller):
+
+ @route(['/odoo_referral/go'], type='json', auth='user', method='POST', website=True)
+ def referral_go(self):
+ return {'link': request.env.user._get_referral_link(reset_count=True)}
diff --git a/addons/odoo_referral/models/__init__.py b/addons/odoo_referral/models/__init__.py
new file mode 100644
index 00000000000..74f3017f7e6
--- /dev/null
+++ b/addons/odoo_referral/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_users
diff --git a/addons/odoo_referral/models/res_users.py b/addons/odoo_referral/models/res_users.py
new file mode 100644
index 00000000000..d678cfb579a
--- /dev/null
+++ b/addons/odoo_referral/models/res_users.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+import uuid
+import requests
+import hmac
+import threading
+
+from hashlib import sha1
+from werkzeug import url_encode
+
+from odoo import api, models
+
+
+DEST_SERVER_URL = 'https://www.odoo.com'
+_logger = logging.getLogger(__name__)
+
+
+class Users(models.Model):
+ _inherit = 'res.users'
+
+ @api.model
+ def get_referral_updates_count_for_current_user(self):
+ token = self.env.user._get_or_generate_referral_token()
+ if not token:
+ return 0
+
+ try:
+ response = requests.get(DEST_SERVER_URL + '/referral/notifications/' + token, timeout=10)
+ except Exception as e:
+ if not getattr(threading.currentThread(), 'testing', False):
+ _logger.exception("Failed to fetch referral gift notifications")
+ return 0
+ if not response.ok:
+ return 0
+
+ return response.json().get('updates_count', 0)
+
+ def _get_or_generate_referral_token(self):
+ self.ensure_one()
+ db_secret = self.env['ir.config_parameter'].sudo().get_param('database.secret').encode('utf-8')
+ db_uuid = self.env['ir.config_parameter'].sudo().get_param('database.uuid')
+ message = (db_uuid + self.env.user.email).encode('utf-8')
+ return hmac.new(db_secret, message, sha1).hexdigest()
+
+ def _get_referral_link(self, reset_count=False):
+ self.ensure_one()
+ params = {
+ 'token': self._get_or_generate_referral_token(),
+ 'referrer_email': self.partner_id.email,
+ }
+ if reset_count:
+ params['reset_count'] = 1
+
+ return DEST_SERVER_URL + '/referral/register?' + url_encode(params)
diff --git a/addons/odoo_referral/static/src/js/systray.js b/addons/odoo_referral/static/src/js/systray.js
new file mode 100644
index 00000000000..4af107d8b7c
--- /dev/null
+++ b/addons/odoo_referral/static/src/js/systray.js
@@ -0,0 +1,54 @@
+odoo.define('systray.systray_odoo_referral', function (require) {
+ "use strict";
+ var localStorage = require('web.local_storage');
+ var SystrayMenu = require('web.SystrayMenu');
+ var Widget = require('web.Widget');
+
+ var ActionMenu = Widget.extend({
+ template: 'systray_odoo_referral.gift_icon',
+ events: {
+ 'click .gift_icon': 'onclick_gifticon',
+ },
+
+ start: function (parent) {
+ var self = this;
+ var lastFetch = localStorage.getItem('odoo_referral.updates_last_fetch');
+ var updatesCount = localStorage.getItem('odoo_referral.updates_count');
+ var hasClicked = localStorage.getItem('odoo_referral.has_clicked');
+ if (hasClicked && (!lastFetch || Date(parseInt(lastFetch)) < Date(new Date().getTime() - (24 * 60 * 60 * 1000)))) {
+ this._rpc({
+ model: 'res.users',
+ method: 'get_referral_updates_count_for_current_user'
+ }, {
+ shadow: true,
+ }).then(function (count) {
+ localStorage.setItem('odoo_referral.updates_last_fetch', Date.now());
+ localStorage.setItem('odoo_referral.updates_count', count);
+ if (count > 0) {
+ self.$('.o_notification_counter').text(count);
+ }
+ });
+ } else {
+ if (updatesCount && updatesCount > 0) {
+ self.$('.o_notification_counter').text(updatesCount);
+ }
+ }
+ return this._super.apply(this, arguments);
+ },
+
+ onclick_gifticon: function () {
+ var self = this;
+ localStorage.setItem('odoo_referral.updates_count', 0);
+ this._rpc({
+ route: '/odoo_referral/go/'
+ }).then(function (result) {
+ localStorage.setItem('odoo_referral.has_clicked', 1);
+ self.$('.o_notification_counter').text('');
+ window.open(result.link, '_blank', 'noopener noreferrer');
+ });
+ },
+ });
+
+ SystrayMenu.Items.push(ActionMenu);
+ return ActionMenu;
+});
diff --git a/addons/odoo_referral/static/src/xml/systray.xml b/addons/odoo_referral/static/src/xml/systray.xml
new file mode 100644
index 00000000000..9e34ac8f856
--- /dev/null
+++ b/addons/odoo_referral/static/src/xml/systray.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/odoo_referral/views/templates.xml b/addons/odoo_referral/views/templates.xml
new file mode 100644
index 00000000000..8efef5ecccd
--- /dev/null
+++ b/addons/odoo_referral/views/templates.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/odoo_referral_portal/__init__.py b/addons/odoo_referral_portal/__init__.py
new file mode 100644
index 00000000000..41ac0af2227
--- /dev/null
+++ b/addons/odoo_referral_portal/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from . import controllers
diff --git a/addons/odoo_referral_portal/__manifest__.py b/addons/odoo_referral_portal/__manifest__.py
new file mode 100644
index 00000000000..6143be4e7c9
--- /dev/null
+++ b/addons/odoo_referral_portal/__manifest__.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+{
+ 'name': "Odoo referral program bridge with portal",
+ 'summary': """Allow you to refer your friends to Odoo and get rewards""",
+ 'category': 'Hidden',
+ 'version': '0.1',
+ 'depends': ['website', 'odoo_referral'],
+ 'data': [
+ 'views/referral_template.xml',
+ ],
+ 'auto_install': True,
+}
diff --git a/addons/odoo_referral_portal/controllers/__init__.py b/addons/odoo_referral_portal/controllers/__init__.py
new file mode 100644
index 00000000000..903b755e71e
--- /dev/null
+++ b/addons/odoo_referral_portal/controllers/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import portal
diff --git a/addons/odoo_referral_portal/controllers/portal.py b/addons/odoo_referral_portal/controllers/portal.py
new file mode 100644
index 00000000000..6a2cc8a06af
--- /dev/null
+++ b/addons/odoo_referral_portal/controllers/portal.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.portal.controllers.portal import CustomerPortal
+from odoo.http import request
+
+
+class CustomerPortal(CustomerPortal):
+
+ def _prepare_portal_layout_values(self):
+ values = super(CustomerPortal, self)._prepare_portal_layout_values()
+ count = request.env['res.users'].get_referral_updates_count_for_current_user()
+ values['referral_updates_count'] = count or ''
+ values['referral_link'] = request.env.user._get_referral_link()
+ return values
diff --git a/addons/odoo_referral_portal/views/referral_template.xml b/addons/odoo_referral_portal/views/referral_template.xml
new file mode 100644
index 00000000000..634807bb83e
--- /dev/null
+++ b/addons/odoo_referral_portal/views/referral_template.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Odoo Referral Program
+
+
+
+
+
+