diff --git a/addons/calendar/__manifest__.py b/addons/calendar/__manifest__.py index 636b7f9e4fa..5b64740b2e9 100644 --- a/addons/calendar/__manifest__.py +++ b/addons/calendar/__manifest__.py @@ -50,7 +50,7 @@ If you need to manage your meetings, you should install the CRM module. 'calendar/static/src/js/calendar_model.js', 'calendar/static/src/js/calendar_view.js', 'calendar/static/src/js/services/calendar_notification_service.js', - 'calendar/static/src/views/*', + 'calendar/static/src/views/**/*', ], 'web.qunit_suite_tests': [ 'calendar/static/tests/**/*', diff --git a/addons/calendar/static/src/views/fields/many2many_attendee.js b/addons/calendar/static/src/views/fields/many2many_attendee.js new file mode 100644 index 00000000000..32970ddb33d --- /dev/null +++ b/addons/calendar/static/src/views/fields/many2many_attendee.js @@ -0,0 +1,30 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +import { Many2ManyTagsAvatarField } from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field"; + +export class Many2ManyAttendee extends Many2ManyTagsAvatarField { + get tags() { + const { partner_ids: partnerIds } = this.props.record.preloadedData; + const tags = super.tags.map((tag) => { + const partner = partnerIds.find((partner) => tag.resId === partner.id); + if (partner) { + tag.className = `o_attendee_border o_attendee_border_${partner.status}`; + } + return tag; + }); + + const organizer = partnerIds.find((partner) => partner.is_organizer); + if (organizer) { + const orgId = organizer.id; + // sort elements according to the partner id + tags.sort((a, b) => { + const a_org = a.id === orgId; + return a_org ? -1 : 1; + }); + } + return tags; + } +} + +registry.category("fields").add("many2manyattendee", Many2ManyAttendee); diff --git a/addons/calendar/static/tests/calendar_tests.js b/addons/calendar/static/tests/calendar_tests.js index 2b304f13c2e..e74e7b126a9 100644 --- a/addons/calendar/static/tests/calendar_tests.js +++ b/addons/calendar/static/tests/calendar_tests.js @@ -1,86 +1,129 @@ /** @odoo-module **/ -import FormView from 'web.FormView'; -import testUtils from "web.test_utils"; +import { getFixture } from "@web/../tests/helpers/utils"; +import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; -var createView = testUtils.createView; +let serverData; +let target; -QUnit.module('calendar', { - beforeEach: function () { - this.data = { - event: { - fields: { - partner_ids: {string: "Partners", type: "many2many", relation: "partner"}, +QUnit.module( + "calendar", + { + beforeEach: function () { + target = getFixture(); + serverData = { + models: { + event: { + fields: { + partner_ids: { + string: "Partners", + type: "many2many", + relation: "partner", + }, + }, + records: [ + { + id: 14, + partner_ids: [1, 2], + }, + ], + }, + partner: { + fields: { + name: { string: "Name", type: "char" }, + }, + records: [ + { + id: 1, + name: "Jesus", + }, + { + id: 2, + name: "Mahomet", + }, + ], + }, }, - records: [{ - id: 14, - partner_ids: [1, 2], - }], - }, - partner: { - fields: { - name: {string: "Name", type: "char"}, - }, - records: [{ - id: 1, - name: "Jesus", - }, { - id: 2, - name: "Mahomet", - }], - }, - }; + }; + setupViewRegistries(); + }, }, -}, function () { - QUnit.test("many2manyattendee widget: basic rendering", async function (assert) { - assert.expect(12); + function () { + QUnit.test("Many2ManyAttendee: basic rendering", async function (assert) { + await makeView({ + type: "form", + resModel: "event", + serverData, + resId: 14, + arch: ` +
+ + `, + mockRPC(route, args) { + if (args.method === "get_attendee_detail") { + assert.step(args.method); + assert.strictEqual( + args.model, + "res.partner", + "the method should only be called on res.partner" + ); + assert.deepEqual( + args.args[0], + [1, 2], + "the partner ids should be passed as argument" + ); + assert.deepEqual( + args.args[1], + [14], + "the event id should be passed as argument" + ); + return Promise.resolve([ + { id: 1, name: "Jesus", status: "accepted", color: 0 }, + { id: 2, name: "Mahomet", status: "tentative", color: 0 }, + ]); + } + }, + }); - var form = await createView({ - View: FormView, - model: 'event', - data: this.data, - res_id: 14, - arch: - '
' + - '' + - '', - mockRPC: function (route, args) { - if (args.method === 'get_attendee_detail') { - assert.strictEqual(args.model, 'res.partner', - "the method should only be called on res.partner"); - assert.deepEqual(args.args[0], [1, 2], - "the partner ids should be passed as argument"); - assert.deepEqual(args.args[1], [14], - "the event id should be passed as argument"); - return Promise.resolve([ - {id: 1, name: "Jesus", status: "accepted", color: 0}, - {id: 2, name: "Mahomet", status: "tentative", color: 0}, - ]); - } - return this._super.apply(this, arguments); - }, + assert.hasClass( + target.querySelector('.o_field_widget[name="partner_ids"] div'), + "o_field_tags" + ); + assert.containsN( + target, + '.o_field_widget[name="partner_ids"] .badge', + 2, + "there should be 2 tags" + ); + const badges = target.querySelectorAll('.o_field_widget[name="partner_ids"] .badge'); + assert.strictEqual( + badges[0].textContent.trim(), + "Jesus", + "the tag should be correctly named" + ); + assert.hasClass( + badges[0].querySelector("img"), + "o_attendee_border_accepted", + "Jesus should attend the meeting" + ); + assert.strictEqual( + badges[1].textContent.trim(), + "Mahomet", + "the tag should be correctly named" + ); + assert.hasClass( + badges[1].querySelector("img"), + "o_attendee_border_tentative", + "Mohamet should still confirm his attendance to the meeting" + ); + assert.containsOnce(badges[0], "img", "should have img tag"); + assert.hasAttrValue( + badges[0].querySelector("img"), + "data-src", + "/web/image/partner/1/avatar_128", + "should have correct avatar image" + ); + assert.verifySteps(["get_attendee_detail"]); }); - - assert.hasClass(form.$('.o_field_widget[name="partner_ids"]'), 'o_field_many2manytags'); - assert.containsN(form, '.o_field_widget[name="partner_ids"] .badge', 2, - "there should be 2 tags"); - assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] .badge:first').text().trim(), "Jesus", - "the tag should be correctly named"); - assert.hasClass(form.$('.o_field_widget[name="partner_ids"] .badge:first img'),'o_attendee_border_accepted', - "Jesus should attend the meeting"); - assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] .badge[data-id="2"]').text().trim(), "Mahomet", - "the tag should be correctly named"); - assert.hasClass(form.el.querySelector('.o_field_widget[name="partner_ids"] .badge[data-id="2"] img'), 'o_attendee_border_tentative', - "Mohamet should still confirm his attendance to the meeting"); - assert.hasClass(form.el.querySelector('.o_field_many2manytags'), 'avatar', - "should have avatar class"); - assert.containsOnce(form, '.o_field_many2manytags.avatar.o_field_widget .badge:first img', - "should have img tag"); - assert.hasAttrValue(form.$('.o_field_many2manytags.avatar.o_field_widget .badge:first img'), - 'data-src', - '/web/image/partner/1/avatar_128', - "should have correct avatar image"); - - form.destroy(); - }); -}); + } +); diff --git a/addons/calendar/static/tests/legacy_calendar_tests.js b/addons/calendar/static/tests/legacy_calendar_tests.js new file mode 100644 index 00000000000..e2b7974626f --- /dev/null +++ b/addons/calendar/static/tests/legacy_calendar_tests.js @@ -0,0 +1,129 @@ +/** @odoo-module **/ + +import FormView from "web.FormView"; +import testUtils from "web.test_utils"; + +var createView = testUtils.createView; + +QUnit.module( + "Legacy calendar", + { + beforeEach: function () { + this.data = { + event: { + fields: { + partner_ids: { string: "Partners", type: "many2many", relation: "partner" }, + }, + records: [ + { + id: 14, + partner_ids: [1, 2], + }, + ], + }, + partner: { + fields: { + name: { string: "Name", type: "char" }, + }, + records: [ + { + id: 1, + name: "Jesus", + }, + { + id: 2, + name: "Mahomet", + }, + ], + }, + }; + }, + }, + function () { + QUnit.test("many2manyattendee widget: basic rendering", async function (assert) { + assert.expect(12); + + var form = await createView({ + View: FormView, + model: "event", + data: this.data, + res_id: 14, + debug: 1, + arch: + "
" + '' + "", + mockRPC: function (route, args) { + if (args.method === "get_attendee_detail") { + assert.strictEqual( + args.model, + "res.partner", + "the method should only be called on res.partner" + ); + assert.deepEqual( + args.args[0], + [1, 2], + "the partner ids should be passed as argument" + ); + assert.deepEqual( + args.args[1], + [14], + "the event id should be passed as argument" + ); + return Promise.resolve([ + { id: 1, name: "Jesus", status: "accepted", color: 0 }, + { id: 2, name: "Mahomet", status: "tentative", color: 0 }, + ]); + } + return this._super.apply(this, arguments); + }, + }); + + assert.hasClass(form.$('.o_field_widget[name="partner_ids"]'), "o_field_many2manytags"); + assert.containsN( + form, + '.o_field_widget[name="partner_ids"] .badge', + 2, + "there should be 2 tags" + ); + assert.strictEqual( + form.$('.o_field_widget[name="partner_ids"] .badge:first').text().trim(), + "Jesus", + "the tag should be correctly named" + ); + assert.hasClass( + form.$('.o_field_widget[name="partner_ids"] .badge:first img'), + "o_attendee_border_accepted", + "Jesus should attend the meeting" + ); + assert.strictEqual( + form.$('.o_field_widget[name="partner_ids"] .badge[data-id="2"]').text().trim(), + "Mahomet", + "the tag should be correctly named" + ); + assert.hasClass( + form.el.querySelector( + '.o_field_widget[name="partner_ids"] .badge[data-id="2"] img' + ), + "o_attendee_border_tentative", + "Mohamet should still confirm his attendance to the meeting" + ); + assert.hasClass( + form.el.querySelector(".o_field_many2manytags"), + "avatar", + "should have avatar class" + ); + assert.containsOnce( + form, + ".o_field_many2manytags.avatar.o_field_widget .badge:first img", + "should have img tag" + ); + assert.hasAttrValue( + form.$(".o_field_many2manytags.avatar.o_field_widget .badge:first img"), + "data-src", + "/web/image/partner/1/avatar_128", + "should have correct avatar image" + ); + + form.destroy(); + }); + } +); diff --git a/addons/web/static/src/views/fields/many2many_tags/tags_list.xml b/addons/web/static/src/views/fields/many2many_tags/tags_list.xml index bb6f13607ef..503e8d72e7f 100644 --- a/addons/web/static/src/views/fields/many2many_tags/tags_list.xml +++ b/addons/web/static/src/views/fields/many2many_tags/tags_list.xml @@ -4,7 +4,7 @@ - +