From 0dd585d1067f383f0bcc76504b18d1013afbc674 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Wed, 30 Sep 2020 11:08:30 -0700 Subject: [PATCH] [ADD] hibou_professional: initial commit for 13.0 --- hibou_professional/__init__.py | 3 + hibou_professional/__manifest__.py | 24 ++ hibou_professional/models/__init__.py | 3 + hibou_professional/models/update.py | 208 +++++++++++++ hibou_professional/static/src/css/web.css | 21 ++ .../static/src/img/hibou_icon_small.png | Bin 0 -> 2483 bytes hibou_professional/static/src/js/core.js | 275 ++++++++++++++++++ .../static/src/xml/templates.xml | 137 +++++++++ .../views/webclient_templates.xml | 11 + 9 files changed, 682 insertions(+) create mode 100644 hibou_professional/__init__.py create mode 100644 hibou_professional/__manifest__.py create mode 100644 hibou_professional/models/__init__.py create mode 100644 hibou_professional/models/update.py create mode 100644 hibou_professional/static/src/css/web.css create mode 100644 hibou_professional/static/src/img/hibou_icon_small.png create mode 100644 hibou_professional/static/src/js/core.js create mode 100644 hibou_professional/static/src/xml/templates.xml create mode 100644 hibou_professional/views/webclient_templates.xml diff --git a/hibou_professional/__init__.py b/hibou_professional/__init__.py new file mode 100644 index 00000000..09434554 --- /dev/null +++ b/hibou_professional/__init__.py @@ -0,0 +1,3 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from . import models diff --git a/hibou_professional/__manifest__.py b/hibou_professional/__manifest__.py new file mode 100644 index 00000000..e254a959 --- /dev/null +++ b/hibou_professional/__manifest__.py @@ -0,0 +1,24 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +{ + 'name': 'Hibou Professional', + 'author': 'Hibou Corp. ', + 'category': 'Tools', + 'depends': ['mail'], + 'version': '13.0.1.0.0', + 'description': """ +Hibou Professional Support and Billing +====================================== + + """, + 'website': 'https://hibou.io/', + 'data': [ + 'views/webclient_templates.xml', + ], + 'qweb': [ + 'static/src/xml/templates.xml', + ], + 'installable': True, + 'auto_install': True, + 'license': 'OPL-1', +} diff --git a/hibou_professional/models/__init__.py b/hibou_professional/models/__init__.py new file mode 100644 index 00000000..1ae9ad83 --- /dev/null +++ b/hibou_professional/models/__init__.py @@ -0,0 +1,3 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from . import update diff --git a/hibou_professional/models/update.py b/hibou_professional/models/update.py new file mode 100644 index 00000000..ef0c517c --- /dev/null +++ b/hibou_professional/models/update.py @@ -0,0 +1,208 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +import datetime +import requests + +from odoo import api, fields, models, release +from odoo.exceptions import UserError + + +class PublisherWarrantyContract(models.AbstractModel): + _inherit = 'publisher_warranty.contract' + + CONFIG_HIBOU_URL = 'https://api.hibou.io/hibouapi/v1/professional' + CONFIG_HIBOU_MESSAGE_URL = 'https://api.hibou.io/hibouapi/v1/professional/message' + CONFIG_HIBOU_QUOTE_URL = 'https://api.hibou.io/hibouapi/v1/professional/quote' + DAYS_ENDING_SOON = 7 + + @api.model + def hibou_professional_status(self): + get_param = self.env['ir.config_parameter'].sudo().get_param + expiration_date = get_param('database.hibou_professional_expiration_date') + expiration_reason = get_param('database.hibou_professional_expiration_reason') + dbuuid = get_param('database.uuid') + expiring = False + expired = False + if expiration_date: + expiration_date_date = fields.Date.from_string(expiration_date) + today = fields.Date.today() + if expiration_date_date < today: + if expiration_reason == 'trial': + expired = 'Your trial of Hibou Professional has ended.' + else: + expired = 'Your Hibou Professional subscription has ended.' + elif expiration_date_date < (today + datetime.timedelta(days=self.DAYS_ENDING_SOON)): + if expiration_reason == 'trial': + expiring = 'Your trial of Hibou Professional is ending soon.' + else: + expiring = 'Your Hibou Professional subscription is ending soon.' + + is_admin = self.env.user.has_group('base.group_erp_manager') + allow_admin_message = get_param('database.hibou_allow_admin_message') + allow_message = get_param('database.hibou_allow_message') + + return { + 'expiration_date': get_param('database.hibou_professional_expiration_date'), + 'expiration_reason': get_param('database.hibou_professional_expiration_reason'), + 'expiring': expiring, + 'expired': expired, + 'professional_code': get_param('database.hibou_professional_code'), + 'dbuuid': dbuuid, + 'is_admin': is_admin, + 'allow_admin_message': allow_admin_message, + 'allow_message': allow_message, + } + + @api.model + def hibou_professional_update_message_preferences(self, allow_admin_message, allow_message): + if self.env.user.has_group('base.group_erp_manager'): + set_param = self.env['ir.config_parameter'].sudo().set_param + set_param('database.hibou_allow_admin_message', allow_admin_message and '1') + set_param('database.hibou_allow_message', allow_message and '1') + return self.hibou_professional_status() + + def _check_message_allow(self): + get_param = self.env['ir.config_parameter'].sudo().get_param + allow_message = get_param('database.hibou_allow_message') + if not allow_message: + allow_message = get_param('database.hibou_allow_admin_message') and self.env.user.has_group( + 'base.group_erp_manager') + if not allow_message: + raise UserError('You are not allowed to send messages at this time.') + + @api.model + def hibou_professional_quote(self): + get_param = self.env['ir.config_parameter'].sudo().get_param + try: + self._hibou_install() + except: + pass + dbuuid = get_param('database.uuid') + dbtoken = get_param('database.hibou_token') + if dbuuid and dbtoken: + return {'url': self.CONFIG_HIBOU_QUOTE_URL + '/%s/%s' % (dbuuid, dbtoken)} + return {} + + @api.model + def hibou_professional_send_message(self, type, priority, subject, body, user_url, res_id): + self._check_message_allow() + get_param = self.env['ir.config_parameter'].sudo().get_param + dbuuid = get_param('database.uuid') + dbtoken = get_param('database.hibou_token') + user_name = self.env.user.name + user_email = self.env.user.email or self.env.user.login + company_name = self.env.user.company_id.name + data = { + 'jsonrpc': '2.0', + 'method': 'call', + 'params': { + 'dbuuid': dbuuid, + 'user_name': user_name, + 'user_email': user_email, + 'user_url': user_url, + 'company_name': company_name, + 'type': type, + 'priority': priority, + 'subject': subject, + 'body': body, + 'res_id': res_id, + }, + } + if dbtoken: + data['params']['dbtoken'] = dbtoken + try: + r = requests.post(self.CONFIG_HIBOU_MESSAGE_URL + '/new', json=data, timeout=30) + r.raise_for_status() + wrapper = r.json() + return wrapper.get('result', {}) + except: + return {'error': 'Error sending message.'} + + @api.model + def hibou_professional_get_messages(self): + self._check_message_allow() + get_param = self.env['ir.config_parameter'].sudo().get_param + dbuuid = get_param('database.uuid') + dbtoken = get_param('database.hibou_token') + try: + r = requests.get(self.CONFIG_HIBOU_MESSAGE_URL + '/get/%s/%s' % (dbuuid, dbtoken), timeout=30) + r.raise_for_status() + # not jsonrpc + return r.json() + except: + return {'error': 'Error retrieving messages, maybe the token is wrong.'} + + @api.model + def hibou_professional_update(self, professional_code): + set_param = self.env['ir.config_parameter'].sudo().set_param + set_param('database.hibou_professional_code', professional_code) + try: + self._hibou_install() + except: + pass + return self.hibou_professional_status() + + def _get_hibou_modules(self): + domain = [('state', 'in', ['installed', 'to upgrade', 'to remove']), ('author', 'ilike', 'hibou')] + module_list = self.env['ir.module.module'].sudo().search_read(domain, ['name']) + return {module['name']: 1 for module in module_list} + + def _get_hibou_message(self): + IrParamSudo = self.env['ir.config_parameter'].sudo() + + dbuuid = IrParamSudo.get_param('database.uuid') + dbtoken = IrParamSudo.get_param('database.hibou_token') + db_create_date = IrParamSudo.get_param('database.create_date') + user = self.env.user.sudo() + professional_code = IrParamSudo.get_param('database.hibou_professional_code') + + module_dictionary = self._get_hibou_modules() + modules = [] + for module, qty in module_dictionary.items(): + modules.append(module if qty == 1 else '%s,%s' % (module, qty)) + + web_base_url = IrParamSudo.get_param('web.base.url') + msg = { + "dbuuid": dbuuid, + "dbname": self._cr.dbname, + "db_create_date": db_create_date, + "version": release.version, + "language": user.lang, + "web_base_url": web_base_url, + "modules": '\n'.join(modules), + "professional_code": professional_code, + } + if dbtoken: + msg['dbtoken'] = dbtoken + msg.update({'company_' + key: value for key, value in user.company_id.read(["name", "email", "phone"])[0].items() if key != 'id'}) + return msg + + def _process_hibou_message(self, result): + if result.get('professional_info'): + set_param = self.env['ir.config_parameter'].sudo().set_param + set_param('database.hibou_professional_expiration_date', result['professional_info'].get('expiration_date')) + set_param('database.hibou_professional_expiration_reason', result['professional_info'].get('expiration_reason', 'trial')) + if result['professional_info'].get('professional_code'): + set_param('database.hibou_professional_code', result['professional_info'].get('professional_code')) + if result['professional_info'].get('dbtoken'): + set_param('database.hibou_token', result['professional_info'].get('dbtoken')) + + def _hibou_install(self): + data = self._get_hibou_message() + data = { + 'jsonrpc': '2.0', + 'method': 'call', + 'params': data, + } + r = requests.post(self.CONFIG_HIBOU_URL, json=data, timeout=30) + r.raise_for_status() + wrapper = r.json() + self._process_hibou_message(wrapper.get('result', {})) + + @api.model + def _get_sys_logs(self): + try: + self._hibou_install() + except: + pass + return super(PublisherWarrantyContract, self)._get_sys_logs() diff --git a/hibou_professional/static/src/css/web.css b/hibou_professional/static/src/css/web.css new file mode 100644 index 00000000..ca02ed75 --- /dev/null +++ b/hibou_professional/static/src/css/web.css @@ -0,0 +1,21 @@ +.hibou_professional_systray .o_mail_systray_dropdown { + max-height: 580px !important; +} +.hibou_professional_systray .o_mail_systray_dropdown_items { + max-height: 578px !important; +} +.hibou_professional_systray .subscription_form button { + margin-top: 6px; +} + +.hibou_professional_systray .hibou-icon-small { + margin-top: -2px; +} + +.hibou_professional_systray .hibou_professional_help { + color: #0a6fa2; +} + +.hibou_professional_systray .o_preview_title span { + font-weight: bold; +} diff --git a/hibou_professional/static/src/img/hibou_icon_small.png b/hibou_professional/static/src/img/hibou_icon_small.png new file mode 100644 index 0000000000000000000000000000000000000000..2ea52f7ee8c9b48364baf8ed8da4e69e73c72bf2 GIT binary patch literal 2483 zcmV;k2~75hP)7|j$53yVp^3i(kQDP^RgB#lviZD#Jw zn^804_1=?Yt8AwzvGHrcU%*ybD@CMaWnoQhn4a^D8p)j7J@<3J_ngzc=YlJmQCYLH z3$i)Oh=fD_nb|pi^%E6%@G(Fzrc8Zka&nxq_I@kTV%Hr`t@3gIT3sS(DyXOt9#pzv z36BbouUNXnTf&Vh9ZLwG2)7$@LE#%mj~Dsb;Z%`79X6toVQ~3`{i$CZ|HUe8WQFDB z1hScB^>ZKRC7xt%dP>$7na!9)2ou837$XeRM>qZA`{?gu!} zmGYPNA^0YGzN7{Az`G8o7bPve4QCtBbg##Z*tg`C>C!ZKIfnXKXt;vf`C`w0&N;e+ z=$d@hCG6}%o5Xt;z5uVrXa~`<0JZ=C010qNS#tmY3ljhU3ljkVnw%H_00-AeL_t(o zg|(M$Y@5{;$A9-e&*QxKrM4S8vEw){G_ba`G^~Yn6I5cbse`RdLLj8Ae1Hn3iEY}n zO-vgIgf>mu(rKDBrglh$i4G040S&CI3@CI(r7xr@P1?{luZ|r%c4EhgV?TcGKG-oy zaSEEo|BK~w&pqdV&bjA4=L%}zWOPCRzXZI%_d0|A`5HPJ&;%%8vNPx})zGN}eh;L8 zpLGWP>QWuCjPpMMJ1e3Kz^{P_unA}eS}M+EMaKdXKpcnx$ABT=r@$2zo!!6#my)PO zULbua%u*%&5s!gU^yEXG`te(FlwIZkfs9eEL;vJs(zWTAD-&fv`7_-LZ|rhAV6Ow)LLJx%X96ZVqWF zgk@FN3fFd!y?5IJktv|HGw7dPAaEbB$985A=k6DgGjk{*7~OCs<7?Z=`aCEpuuo?2 zU5FB}8O+{uD~L)q6g2+zHKGNRZi@;L6?%)REAT7 zQF2}v=aW-(OilwZpe%ALSD4Ur%%ZWpFyF_K8rKQ=)s+|0SH8(DYYC~{^F$Fr}I zdEk!gfa`VOW|_`Xcf22fbjZ*6+6Vw!uUSpR?*(9buE2&!D`B6P{qLP7+vFzQdmaR2 zeQtD3a{K0MaN8T0H%nMb5%jL0+2i8P-T|U(BLqJf#4|cU-LZb;-B~QR^Ja-s8;qe? zHC@R_3jl3R?yB=sqbY(v`3t)a_TsiTur3@ZlhOp!vfRn*!U5d&1_1UQJx}D}eY|{X zh=|`ysL2h$Wcx=Y)raB$>!p}4Uat>-L?G)gE4O%D0Q~rcce&+v`YrmxJfEq3n)#iE(oi9 zRa=$cqZbn-vgNZ;Z)g~r#HzHH5(2A|fs&eEU_g^AGM{@HIOnS z0mE!>sV=zUX#mDj%?z>U520YMP#ChQ|+G*uEKnXvLOuB3<=kmOISQkwTh_+Rb+%%7rhiC6><6KN{!8juv`; zaVM5iXi^YMXXqP=BLtjF&jGMq3i?LkgneGVbwdaDY+j8N0wJJpG)^p?sn{N`q#4Zi z77#+yMWKl0vXj4YBlT~;k1L)cd~$%{&JNx^J4iG&P1xr_*EGgc(+ortSW2VH`alq5!krhHY*h??{~0hkIFdv=3=1N`4QS2fvBc zRQ})^{ey9FZr8puxx2r-W`V7kFJS-M8`S@&7g02qL}G@U$$onqW~7B$&nM`NM=H@PI%XVfEZG5r_yd^{3T@%0|$8)cP z`qa1=e71b7rGQ*o%f>k#m~{l&MD zi_*LpUbhqf%JP>ok(#Eks72=sMUs{4*5BmD>#jW+X_M15?mrB$H`LvAvPz(W9U@;i z;@a~v!u;4PYl*XHJjLjEvMMW=XL1RtOCbtHoV#B_6pC*G4=%{71VY_ibHMG!+2I4O zKmHvSO|*+)Gju#F9C%hZsxq(Jf!FQ8(6yR-FiW`p@B+s9v2NgwP^CE 0) { + this.$('#hibou_subject_selection').show(); + this.$('.hibou_subject_selection_option').hide().attr('disabled', true); + this.$('.hibou_subject_selection_option.' + selected_type).show().attr('disabled', false); + var selected_subject = this.$('.hibou_subject_selection_option.' + selected_type)[0]; + this.$('select.hibou_subject_selection').val(selected_subject.value); + } else if (selected_type) { + this.$('select.hibou_subject_selection').val('0'); + this.$('#hibou_subject_selection').hide(); + } else { + this.$('#hibou_subject_selection').hide(); + this.$('#hibou_message_priority').hide(); + this.$('#hibou_message_subject').hide(); + } + this.update_subject_selection(); + }, + + update_subject_selection: function(el) { + var selected_subject = this.$('select.hibou_subject_selection').val(); + if (selected_subject == '0') { + this.$('#hibou_message_priority').show(); + this.$('#hibou_message_subject').show(); + } else { + this.$('#hibou_message_priority').hide(); + this.$('#hibou_message_subject').hide(); + } + }, + + update_message_subjects: function(subjects_by_type) { + // TODO actually update instead of overriding... + this.message_subjects = subjects_by_type; + this.renderElement(); + }, + + button_update_subscription: function() { + var self = this; + var professional_code = self.$('input.hibou_professional_code').val(); + if (!professional_code) { + alert('Please enter a subscription code first.'); + return; + } + self.$('.update_subscription').prop('disabled', 'disabled'); + self._rpc({ + model: 'publisher_warranty.contract', + method: 'hibou_professional_update', + args: [professional_code], + }).then(function (result) { + self.$('.update_subscription').prop('disabled', false); + self.handleStatusUpdate(result); + }); + }, + + button_update_message_preferences: function() { + var self = this; + var allow_admin_message = self.$('input.hibou_allow_admin_message').prop('checked'); + var allow_message = self.$('input.hibou_allow_message').prop('checked'); + self.$('.update_message_preferences').prop('disabled', 'disabled'); + self._rpc({ + model: 'publisher_warranty.contract', + method: 'hibou_professional_update_message_preferences', + args: [allow_admin_message, allow_message], + }).then(function (result) { + self.$('.update_message_preferences').prop('disabled', false); + self.handleStatusUpdate(result); + }); + }, + + button_quote: function() { + var self = this; + var message_p = self.$('.button-quote-link p'); + message_p.text('Retrieving URL...'); + self._rpc({ + model: 'publisher_warranty.contract', + method: 'hibou_professional_quote', + }).then(function (result) { + if (result && result['url']) { + self.quote_url = result.url + self.$('.button-quote-link').attr('href', self.quote_url); + message_p.text('Quote URL ready. Click again!'); + } else { + message_p.text('Error with quote url. Maybe the database token is incorrect.'); + } + }); + }, + + button_send_message: function() { + var self = this; + var message_type = self.$('select.hibou_message_type').val(); + var message_priority = self.$('select.hibou_message_priority').val(); + var message_subject = self.$('input.hibou_message_subject').val(); + var message_subject_id = self.$('select.hibou_subject_selection').val(); + var current_url = window.location.href; + if (message_subject_id == '0' && (!message_subject || message_subject.length < 3)) { + alert('Please enter a longer subject.'); + return; + } + var message_body = self.$('textarea.hibou_message_body').val(); + self.$('.hibou_send_message').prop('disabled', 'disabled'); + self._rpc({ + model: 'publisher_warranty.contract', + method: 'hibou_professional_send_message', + args: [message_type, message_priority, message_subject, message_body, current_url, message_subject_id], + }).then(function (result) { + // TODO result will have a subject to add to the subjects and re-render. + self.$('.hibou_send_message').prop('disabled', false); + var message_response = self.$('.hibou_message_response'); + var access_link = self.$('.hibou_message_response a'); + var message_form = self.$('.hibou_message_form'); + if (!result) { + access_link.text('An error has occured.') + } else { + if (result.error) { + access_link.text(result.error); + } else { + access_link.text(result.message || 'Your message has been received.') + } + if (result.access_url) { + access_link.attr('href', result.access_url); + } + } + message_response.show(); + message_form.hide(); + }); + }, + + button_get_messages: function() { + var self = this; + var $button = this.$('.hibou_get_messages'); + $button.prop('disabled', 'disabled'); + self._rpc({ + model: 'publisher_warranty.contract', + method: 'hibou_professional_get_messages', + args: [], + }).then(function (result) { + $button.prop('disabled', false); + if (result['message_subjects']) { + self.update_message_subjects(result.message_subjects); + setTimeout(function () { + self.$('.dropdown-toggle').click(); + }, 100); + } else if (result['error']) { + self.set_error(result['error']); + } + }); + }, + + renderElement: function() { + var self = this; + this._super(); + + this.update_message_type(); + this.update_subject_selection(); + + this.$('select.hibou_message_type').on('change', function(el) { + self.update_message_type(el); + }); + this.$('select.hibou_subject_selection').on('change', function(el) { + self.update_subject_selection(el); + }); + + // Update Subscription Button + this.$('.update_subscription').on('click', function(e){ + e.preventDefault(); + e.stopPropagation(); + self.button_update_subscription(); + }); + + this.$('.hibou_get_messages').on('click', function(e){ + e.preventDefault(); + e.stopPropagation(); + self.button_get_messages(); + }); + + // Retrieve quote URL + this.$('.button-quote-link').on('click', function(e){ + if (self.quote_url) { + return; // allow default url click event + } + e.preventDefault(); + e.stopPropagation(); + self.button_quote(); + }); + + // Update Message Preferences Button + this.$('.update_message_preferences').on('click', function(e){ + e.preventDefault(); + e.stopPropagation(); + self.button_update_message_preferences(); + }); + + // Send Message Button + this.$('.hibou_send_message').on('click', function(e){ + e.preventDefault(); + e.stopPropagation(); + self.button_send_message(); + }); + + // Kill the default click event + this.$('.hibou_message_form_container').on('click', function (e) { + //e.preventDefault(); + e.stopPropagation(); + }) + }, + + handleStatusUpdate: function(status) { + this.expiration_date = status.expiration_date; + this.expiration_reason = status.expiration_reason; + this.professional_code = status.professional_code; + this.types = [['lead', 'Sales'], ['ticket', 'Support']]; + if (this.professional_code) { + this.types.push(['task', 'Project Manager/Developer']) + } + this.expiring = status.expiring; + this.expired = status.expired; + this.dbuuid = status.dbuuid; + this.is_admin = status.is_admin; + this.allow_admin_message = status.allow_admin_message; + this.allow_message = status.allow_message; + this.renderElement(); + }, + +}); + +SystrayMenu.Items.push(HibouProfessionalSystrayWidget); + +return { + HibouProfessionalSystrayWidget: HibouProfessionalSystrayWidget, +}; + +}); \ No newline at end of file diff --git a/hibou_professional/static/src/xml/templates.xml b/hibou_professional/static/src/xml/templates.xml new file mode 100644 index 00000000..f8fa8154 --- /dev/null +++ b/hibou_professional/static/src/xml/templates.xml @@ -0,0 +1,137 @@ + + + +
  • + +