diff options
| author | Xavier Dubuc <xdu@odoo.com> | 2020-11-10 08:59:25 +0000 |
|---|---|---|
| committer | Sébastien Theys <seb@odoo.com> | 2020-11-30 15:21:27 +0000 |
| commit | d9aa362914945e6cb095b04fa94cfb3469abd907 (patch) | |
| tree | d234604da02879d539155206949e112d437957c2 /addons | |
| parent | 24d52d4a8d0f475bb62b6653c08ce409e27e1d58 (diff) | |
[FIX] hr_holidays: bring back the out of office panel in threads
task-2277511
closes odoo/odoo#61586
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Diffstat (limited to 'addons')
11 files changed, 269 insertions, 33 deletions
diff --git a/addons/hr_holidays/i18n/hr_holidays.pot b/addons/hr_holidays/i18n/hr_holidays.pot index 62cc0887314..c952b719400 100644 --- a/addons/hr_holidays/i18n/hr_holidays.pot +++ b/addons/hr_holidays/i18n/hr_holidays.pot @@ -3308,3 +3308,10 @@ msgstr "" #: model_terms:ir.ui.view,arch_db:hr_holidays.hr_leave_view_kanban msgid "validated" msgstr "" + +#. module: hr_holidays +#. openerp-web +#: code:addons/hr_holidays/static/src/bugfix/bugfix.js:0 +#, python-format +msgid "Out of office until %s" +msgstr "" diff --git a/addons/hr_holidays/static/src/bugfix/bugfix.js b/addons/hr_holidays/static/src/bugfix/bugfix.js index 1f0782785eb..41d3e558cc0 100644 --- a/addons/hr_holidays/static/src/bugfix/bugfix.js +++ b/addons/hr_holidays/static/src/bugfix/bugfix.js @@ -8,3 +8,81 @@ odoo.define('hr_holidays/static/src/bugfix/bugfix.js', function (require) { 'use strict'; }); + +// FIXME move me in hr_holidays/static/src/models/partner/partner.js +odoo.define('hr_holidays/static/src/models/partner/partner.js', function (require) { +'use strict'; + +const { + registerClassPatchModel, + registerFieldPatchModel, + registerInstancePatchModel, +} = require('mail/static/src/model/model_core.js'); +const { attr, one2one } = require('mail/static/src/model/model_field.js'); +const { clear } = require('mail/static/src/model/model_field_command.js'); + +const { str_to_datetime } = require('web.time'); + +registerClassPatchModel('mail.partner', 'hr_holidays/static/src/models/partner/partner.js', { + /** + * @override + */ + convertData(data) { + const data2 = this._super(data); + if ('out_of_office_date_end' in data) { + data2.outOfOfficeDateEnd = data.out_of_office_date_end ? data.out_of_office_date_end : clear(); + } + return data2; + }, +}); + +registerInstancePatchModel('mail.partner', 'hr_holidays/static/src/models/partner/partner.js', { + /** + * @private + */ + _computeOutOfOfficeText() { + if (!this.outOfOfficeDateEnd) { + return clear(); + } + if (!this.env.messaging.locale.language) { + return clear(); + } + const currentDate = new Date(); + const date = str_to_datetime(this.outOfOfficeDateEnd); + const options = { day: 'numeric', month: 'short' }; + if (currentDate.getFullYear() !== date.getFullYear()) { + options.year = 'numeric'; + } + const localeCode = this.env.messaging.locale.language.replace(/_/g,'-'); + const formattedDate = date.toLocaleDateString(localeCode, options); + return _.str.sprintf(this.env._t("Out of office until %s"), formattedDate); + }, + +}); + +registerFieldPatchModel('mail.partner', 'hr/static/src/models/partner/partner.js', { + /** + * Serves as compute dependency. + */ + locale: one2one('mail.locale', { + related: 'messaging.locale', + }), + /** + * Date of end of the out of office period of the partner as string. + * String is expected to use Odoo's datetime string format + * (examples: '2011-12-01 15:12:35.832' or '2011-12-01 15:12:35'). + */ + outOfOfficeDateEnd: attr(), + /** + * Text shown when partner is out of office. + */ + outOfOfficeText: attr({ + compute: '_computeOutOfOfficeText', + dependencies: [ + 'locale', + 'outOfOfficeDateEnd', + ], + }), +}); + +}); diff --git a/addons/hr_holidays/static/src/bugfix/bugfix_tests.js b/addons/hr_holidays/static/src/bugfix/bugfix_tests.js index a18e79a4020..6f655603071 100644 --- a/addons/hr_holidays/static/src/bugfix/bugfix_tests.js +++ b/addons/hr_holidays/static/src/bugfix/bugfix_tests.js @@ -16,3 +16,95 @@ QUnit.module('bugfix_tests.js', { }); }); + +// FIXME move me in hr_holidays/static/src/components/thread_view/thread_view_tests.js +odoo.define('hr_holidays/static/src/components/thread_view/thread_view_tests.js', function (require) { +'use strict'; + +const components = { + ThreadView: require('mail/static/src/components/thread_view/thread_view.js'), +}; +const { + afterEach, + beforeEach, + createRootComponent, + start, +} = require('mail/static/src/utils/test_utils.js'); + +QUnit.module('hr_holidays', {}, function () { +QUnit.module('components', {}, function () { +QUnit.module('thread_view', {}, function () { +QUnit.module('thread_view_tests.js', { + beforeEach() { + beforeEach(this); + + /** + * @param {mail.thread_view} threadView + * @param {Object} [otherProps={}] + */ + this.createThreadViewComponent = async (threadView, otherProps = {}) => { + const target = this.widget.el; + const props = Object.assign({ threadViewLocalId: threadView.localId }, otherProps); + await createRootComponent(this, components.ThreadView, { props, target }); + }; + + this.start = async params => { + const { afterEvent, env, widget } = await start(Object.assign({}, params, { + data: this.data, + })); + this.afterEvent = afterEvent; + this.env = env; + this.widget = widget; + }; + }, + afterEach() { + afterEach(this); + }, +}); + +QUnit.test('out of office message on direct chat with out of office partner', async function (assert) { + assert.expect(2); + + // Returning date of the out of office partner, simulates he'll be back in a month + const returningDate = moment.utc().add(1, 'month'); + // Needed partner & user to allow simulation of message reception + this.data['res.partner'].records.push({ + id: 11, + name: "Foreigner partner", + out_of_office_date_end: returningDate.format("YYYY-MM-DD HH:mm:ss"), + }); + this.data['mail.channel'].records = [{ + channel_type: 'chat', + id: 20, + members: [this.data.currentPartnerId, 11], + }]; + await this.start(); + const thread = this.env.models['mail.thread'].findFromIdentifyingData({ + id: 20, + model: 'mail.channel' + }); + const threadViewer = this.env.models['mail.thread_viewer'].create({ + hasThreadView: true, + thread: [['link', thread]], + }); + await this.createThreadViewComponent(threadViewer.threadView, { hasComposer: true }); + assert.containsOnce( + document.body, + '.o_ThreadView_outOfOffice', + "should have an out of office alert on thread view" + ); + const formattedDate = returningDate.toDate().toLocaleDateString( + this.env.messaging.locale.language.replace(/_/g,'-'), + { day: 'numeric', month: 'short' } + ); + assert.ok( + document.querySelector('.o_ThreadView_outOfOffice').textContent.includes(formattedDate), + "out of office message should mention the returning date" + ); +}); + +}); +}); +}); + +}); diff --git a/addons/hr_holidays/static/src/components/thread_view/thread_view.js b/addons/hr_holidays/static/src/components/thread_view/thread_view.js index 89923ff0384..c07ab2189a9 100644 --- a/addons/hr_holidays/static/src/components/thread_view/thread_view.js +++ b/addons/hr_holidays/static/src/components/thread_view/thread_view.js @@ -5,38 +5,9 @@ const components = { ThreadView: require('mail/static/src/components/thread_view/thread_view.js'), }; -const { str_to_datetime } = require('web.time'); const { patch } = require('web.utils'); patch(components.ThreadView, 'hr_holidays/static/src/components/thread_view/thread_view.js', { - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * Returns the "out of office" text for the correspondent of the thread if - * applicable. - * - * @returns {string} - */ - getOutOfOfficeText() { - if (!this.threadView.thread.correspondent) { - return ""; - } - if (!this.threadView.thread.correspondent.out_of_office_date_end) { - return ""; - } - const currentDate = new Date(); - const date = str_to_datetime(this.threadView.thread.correspondent.out_of_office_date_end); - const options = { day: 'numeric', month: 'short' }; - if (currentDate.getFullYear() !== date.getFullYear()) { - options.year = 'numeric'; - } - const formattedDate = date.toLocaleDateString(window.navigator.language, options); - return _.str.sprintf(this.env._t("Out of office until %s."), formattedDate); - }, - //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- diff --git a/addons/hr_holidays/static/src/components/thread_view/thread_view.xml b/addons/hr_holidays/static/src/components/thread_view/thread_view.xml index f5e0dce55d8..796dcfba651 100644 --- a/addons/hr_holidays/static/src/components/thread_view/thread_view.xml +++ b/addons/hr_holidays/static/src/components/thread_view/thread_view.xml @@ -2,8 +2,8 @@ <templates xml:space="preserve"> <t t-inherit="mail.ThreadView" t-inherit-mode="extension"> <xpath expr="//*[@name='loadingCondition']" position="before"> - <t t-if="threadView.thread.correspondent and threadView.thread.correspondent.out_of_office_date_end"> - <div class="o_ThreadView_outOfOffice alert alert-primary" t-esc="getOutOfOfficeText()" role="alert"/> + <t t-if="threadView.thread.correspondent and threadView.thread.correspondent.outOfOfficeText"> + <div class="o_ThreadView_outOfOffice alert alert-primary" t-esc="threadView.thread.correspondent.outOfOfficeText" role="alert"/> </t> </xpath> </t> diff --git a/addons/hr_holidays/static/tests/helpers/mock_models.js b/addons/hr_holidays/static/tests/helpers/mock_models.js new file mode 100644 index 00000000000..8513f29d2bf --- /dev/null +++ b/addons/hr_holidays/static/tests/helpers/mock_models.js @@ -0,0 +1,28 @@ +odoo.define('hr_holidays/static/tests/helpers/mock_models.js', function (require) { +'use strict'; + +const MockModels = require('mail/static/tests/helpers/mock_models.js'); + +MockModels.patch('hr_holidays/static/tests/helpers/mock_models.js', T => + class extends T { + + //---------------------------------------------------------------------- + // Public + //---------------------------------------------------------------------- + + /** + * @override + */ + static generateData() { + const data = super.generateData(...arguments); + Object.assign(data['res.partner'].fields, { + // Not a real field but ease the testing + out_of_office_date_end: { type: 'datetime' }, + }); + return data; + } + + } +); + +}); diff --git a/addons/hr_holidays/static/tests/helpers/mock_server.js b/addons/hr_holidays/static/tests/helpers/mock_server.js new file mode 100644 index 00000000000..f4b8f6404c0 --- /dev/null +++ b/addons/hr_holidays/static/tests/helpers/mock_server.js @@ -0,0 +1,29 @@ +odoo.define('hr_holidays/static/tests/helpers/mock_server.js', function (require) { +'use strict'; + +require('mail.MockServer'); // ensure mail overrides are applied first + +const MockServer = require('web.MockServer'); + +MockServer.include({ + /** + * Overrides to add visitor information to livechat channels. + * + * @override + */ + _mockMailChannelPartnerInfo(ids, extra_info) { + const partnerInfos = this._super(...arguments); + const partners = this._getRecords( + 'res.partner', + [['id', 'in', ids]], + { active_test: false }, + ); + for (const partner of partners) { + // Not a real field but ease the testing + partnerInfos[partner.id].out_of_office_date_end = partner.out_of_office_date_end; + } + return partnerInfos; + }, +}); + +}); diff --git a/addons/hr_holidays/views/hr_leave_template.xml b/addons/hr_holidays/views/hr_leave_template.xml index f70aa21064e..cfdeeac2c78 100644 --- a/addons/hr_holidays/views/hr_leave_template.xml +++ b/addons/hr_holidays/views/hr_leave_template.xml @@ -19,6 +19,8 @@ <template id="qunit_suite" name="hr_holidays_qunit_suite" inherit_id="web.qunit_suite_tests"> <xpath expr="." position="inside"> <script type="text/javascript" src="/hr_holidays/static/src/bugfix/bugfix_tests.js"></script> + <script type="text/javascript" src="/hr_holidays/static/tests/helpers/mock_models.js"/> + <script type="text/javascript" src="/hr_holidays/static/tests/helpers/mock_server.js"/> <script type="text/javascript" src="/hr_holidays/static/tests/test_leave_stats_widget.js"></script> </xpath> </template> diff --git a/addons/mail/static/src/js/core/translation.js b/addons/mail/static/src/js/core/translation.js index a8db8cebc57..faecafaff03 100644 --- a/addons/mail/static/src/js/core/translation.js +++ b/addons/mail/static/src/js/core/translation.js @@ -14,9 +14,10 @@ TranslationDataBase.include({ if (Component.env.messaging) { // Update messaging locale whenever the translation bundle changes. // In particular if messaging is created before the end of the - // `load_translations` RPC, the default text direction has to be - // updated by the received one. + // `load_translations` RPC, the default values have to be + // updated by the received ones. Component.env.messaging.locale.update({ + language: this.parameters.code, textDirection: this.parameters.direction, }); } diff --git a/addons/mail/static/src/models/locale/locale.js b/addons/mail/static/src/models/locale/locale.js index 4007dbc796c..50167f07c2f 100644 --- a/addons/mail/static/src/models/locale/locale.js +++ b/addons/mail/static/src/models/locale/locale.js @@ -16,6 +16,14 @@ function factory(dependencies) { * @private * @returns {string} */ + _computeLanguage() { + return this.env._t.database.parameters.code; + } + + /** + * @private + * @returns {string} + */ _computeTextDirection() { return this.env._t.database.parameters.direction; } @@ -23,6 +31,12 @@ function factory(dependencies) { } Locale.fields = { + /** + * Language used by interface, formatted like {language ISO 2}_{country ISO 2} (eg: fr_FR). + */ + language: attr({ + compute: '_computeLanguage', + }), textDirection: attr({ compute: '_computeTextDirection', }), diff --git a/addons/mail/static/src/models/partner/partner.js b/addons/mail/static/src/models/partner/partner.js index 95d2e2794ac..3de505426ec 100644 --- a/addons/mail/static/src/models/partner/partner.js +++ b/addons/mail/static/src/models/partner/partner.js @@ -259,6 +259,14 @@ function factory(dependencies) { /** * @private + * @returns {mail.messaging} + */ + _computeMessaging() { + return [['link', this.env.messaging]]; + } + + /** + * @private * @returns {string|undefined} */ _computeNameOrDisplayName() { @@ -308,6 +316,12 @@ function factory(dependencies) { messagesAsAuthor: one2many('mail.message', { inverse: 'author', }), + /** + * Serves as compute dependency. + */ + messaging: many2one('mail.messaging', { + compute: '_computeMessaging', + }), model: attr({ default: 'res.partner', }), |
