[IMP] account: Add a new boolean_favorite widget

Purpose
=======

Projects and soon sales teams have a manual "favorite" button that calls a toggle_favorite method
It should actually be a widget on a boolean field

Specifications
==============

Develop a favorite widget for kanban view that allows to toggle a boolean field
Probably update boolean field to allow inverse method on it

Functionally nothing changed.
This commit is contained in:
Jigar Patel
2017-08-09 15:11:53 +02:00
committed by Yannick Tivisse
parent dd427405e2
commit 2adc9d5032
11 changed files with 217 additions and 50 deletions
@@ -26,11 +26,6 @@ class account_journal(models.Model):
kanban_dashboard_graph = fields.Text(compute='_kanban_dashboard_graph')
show_on_dashboard = fields.Boolean(string='Show journal on dashboard', help="Whether this journal should be displayed on the dashboard or not", default=True)
@api.multi
def toggle_favorite(self):
self.write({'show_on_dashboard': False if self.show_on_dashboard else True})
return False
def _graph_title_and_key(self):
if self.type == 'sale':
return ['', _('Sales: Untaxed Total')]
@@ -209,7 +209,7 @@
<div groups="account.group_account_manager" class="row o_kanban_card_settings">
<div class="col-xs-6">
<a type="object" name="toggle_favorite"><i t-attf-class="fa o_dashboard_star #{record.show_on_dashboard.raw_value ? 'fa-star' : 'fa-star-o'}" title="Click to add/remove from favorite"/> Favorite</a>
<field name="show_on_dashboard" widget="boolean_favorite" />
</div>
<div class="col-xs-6 text-right">
<a t-if="widget.editable" type="edit">Settings</a>
+13 -14
View File
@@ -151,6 +151,18 @@ class Project(models.Model):
for project in self:
project.is_favorite = self.env.user in project.favorite_user_ids
def _inverse_is_favorite(self):
favorite_projects = not_fav_projects = self.env['project.project'].sudo()
for project in self:
if self.env.user in project.favorite_user_ids:
favorite_projects |= project
else:
not_fav_projects |= project
# Project User has no write access for project.
not_fav_projects.write({'favorite_user_ids': [(4, self.env.uid)]})
favorite_projects.write({'favorite_user_ids': [(3, self.env.uid)]})
def _get_default_favorite_user_ids(self):
return [(6, 0, [self.env.uid])]
@@ -172,7 +184,7 @@ class Project(models.Model):
'res.users', 'project_favorite_user_rel', 'project_id', 'user_id',
default=_get_default_favorite_user_ids,
string='Members')
is_favorite = fields.Boolean(compute='_compute_is_favorite', string='Show Project on dashboard',
is_favorite = fields.Boolean(compute='_compute_is_favorite', inverse='_inverse_is_favorite', string='Show Project on dashboard',
help="Whether this project should be displayed on the dashboard or not")
label_tasks = fields.Char(string='Use Tasks as', default='Tasks', help="Gives label to tasks on project's kanban view.")
tasks = fields.One2many('project.task', 'project_id', string="Task Activities")
@@ -278,19 +290,6 @@ class Project(models.Model):
self.mapped('tasks').message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
return super(Project, self).message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
@api.multi
def toggle_favorite(self):
favorite_projects = not_fav_projects = self.env['project.project'].sudo()
for project in self:
if self.env.user in project.favorite_user_ids:
favorite_projects |= project
else:
not_fav_projects |= project
# Project User has no write access for project.
not_fav_projects.write({'favorite_user_ids': [(4, self.env.uid)]})
favorite_projects.write({'favorite_user_ids': [(3, self.env.uid)]})
@api.multi
def close_dialog(self):
return {'type': 'ir.actions.act_window_close'}
@@ -38,20 +38,6 @@
}
}
.o_dashboard_star {
font-size: 16px;
&.fa-star-o {
color: @odoo-main-color-muted;
&:hover {
color: gold;
}
}
&.fa-star {
color: gold;
}
}
.o_project_kanban_boxes {
width: 30%;
.o-flex(0, 0, auto);
+1 -2
View File
@@ -263,7 +263,6 @@
<field name="alias_id"/>
<field name="alias_name"/>
<field name="alias_domain"/>
<field name="is_favorite"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)} oe_kanban_global_click">
@@ -296,7 +295,7 @@
</div>
<div class="o_project_kanban_manage">
<a class="o_kanban_manage_toggle_button o_left" href="#"><i class="fa fa-ellipsis-v" /></a>
<a type="object" name="toggle_favorite" class="o_right"><i t-attf-class="oe_inline fa o_dashboard_star #{record.is_favorite.raw_value ? 'fa-star' : 'fa-star-o'}" title="Add/remove from favorite"/></a>
<span class="o_right"><field name="is_favorite" widget="boolean_favorite" nolabel="1" /></span>
</div>
</div>
+8 -9
View File
@@ -55,7 +55,7 @@ class CrmTeam(models.Model):
default=_get_default_favorite_user_ids)
is_favorite = fields.Boolean(
string='Show on dashboard',
compute='_compute_is_favorite', inverse='_set_is_favorite',
compute='_compute_is_favorite', inverse='_inverse_is_favorite',
help="Favorite teams to display them in the dashboard and access them easily.")
reply_to = fields.Char(string='Reply-To',
help="The email address put in the 'Reply-To' of all emails sent by Odoo about cases in this sales channel")
@@ -95,6 +95,13 @@ class CrmTeam(models.Model):
for team in self:
team.is_favorite = self.env.user in team.favorite_user_ids
def _inverse_is_favorite(self):
sudoed_self = self.sudo()
to_fav = sudoed_self.filtered(lambda team: self.env.user not in team.favorite_user_ids)
to_fav.write({'favorite_user_ids': [(4, self.env.uid)]})
(sudoed_self - to_fav).write({'favorite_user_ids': [(3, self.env.uid)]})
return True
def _graph_get_dates(self, today):
""" return a coherent start and end date for the dashboard graph according to the graph settings.
"""
@@ -286,14 +293,6 @@ class CrmTeam(models.Model):
self._add_members_to_favorites()
return res
@api.multi
def toggle_favorite(self):
sudoed_self = self.sudo()
to_fav = sudoed_self.filtered(lambda team: self.env.user not in team.favorite_user_ids)
to_fav.write({'favorite_user_ids': [(4, self.env.uid)]})
(sudoed_self - to_fav).write({'favorite_user_ids': [(3, self.env.uid)]})
return True
def _add_members_to_favorites(self):
for team in self:
team.favorite_user_ids = [(4, member.id) for member in team.member_ids]
@@ -70,11 +70,7 @@
</div>
<div class="row mb16">
<div class="col-xs-6">
<a type="object" name="toggle_favorite">
<i t-attf-class="fa o_dashboard_star #{record.is_favorite.raw_value ? 'fa-star' : 'fa-star-o'}" title="Click to add/remove from favorite"/>
<l t-if="record.is_favorite.raw_value"> Remove from My Favorites</l>
<l t-elif="!record.is_favorite.raw_value"> Add to My Favorites</l>
</a>
<field name="is_favorite" widget="boolean_favorite" />
</div>
</div>
</div>
@@ -1449,6 +1449,58 @@ var StateSelectionWidget = AbstractField.extend({
},
});
var FavoriteWidget = AbstractField.extend({
className: 'o_favorite',
events: {
'click': '_setFavorite'
},
supportedFieldTypes: ['boolean'],
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* A boolean field is always set since false is a valid value.
*
* @override
*/
isSet: function () {
return true;
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Render favorite icon based on state
*
* @override
* @private
*/
_render: function () {
var template = this.attrs.nolabel ? '<a href="#"><i class="fa %s" title="%s"></i></a>' : '<a href="#"><i class="fa %s"></i> %s</a>';
this.$el.empty().append(_.str.sprintf(template, this.value ? 'fa-star' : 'fa-star-o', this.value ? _t('Remove from Favorites') : _t('Add to Favorites')));
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Toggle favorite state
*
* @private
* @param {MouseEvent} event
*/
_setFavorite: function (event) {
event.preventDefault();
event.stopPropagation();
this._setValue(!this.value);
},
});
var LabelSelection = AbstractField.extend({
supportedFieldTypes: ['selection'],
@@ -2350,6 +2402,7 @@ return {
AttachmentImage: AttachmentImage,
LabelSelection: LabelSelection,
StateSelectionWidget: StateSelectionWidget,
FavoriteWidget: FavoriteWidget,
PriorityWidget: PriorityWidget,
StatInfo: StatInfo,
UrlWidget: UrlWidget,
@@ -40,6 +40,7 @@ registry
.add('label_selection', basic_fields.LabelSelection)
.add('state_selection', basic_fields.StateSelectionWidget)
.add('kanban_state_selection', basic_fields.StateSelectionWidget)
.add('boolean_favorite', basic_fields.FavoriteWidget)
.add('boolean_button', basic_fields.FieldBooleanButton)
.add('boolean_toggle', basic_fields.BooleanToggle)
.add('statinfo', basic_fields.StatInfo)
+16
View File
@@ -180,6 +180,22 @@
}
}
// Favorite
&.o_favorite {
i.fa {
font-size: 16px;
}
i.fa-star-o {
color: @odoo-main-color-muted;
&:hover {
color: gold;
}
}
i.fa-star {
color: gold;
}
}
// Specific success color for toggle_button widget
.fa.o_toggle_button_success {
color: @brand-success;
@@ -2997,6 +2997,129 @@ QUnit.module('basic_fields', {
});
QUnit.module('FavoriteWidget');
QUnit.test('favorite widget in kanban view', function (assert) {
assert.expect(4);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '<kanban class="o_kanban_test">' +
'<templates>' +
'<t t-name="kanban-box">' +
'<div>' +
'<field name="bar" widget="boolean_favorite" />' +
'</div>' +
'</t>' +
'</templates>' +
'</kanban>',
domain: [['id', '=', 1]],
});
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
'should be favorite');
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
'the label should say "Remove from Favorites"');
// click on favorite
kanban.$('.o_field_widget.o_favorite').click();
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star').length, 0,
'should not be favorite');
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Add to Favorites',
'the label should say "Add to Favorites"');
kanban.destroy();
});
QUnit.test('favorite widget in form view', function (assert) {
assert.expect(10);
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<sheet>' +
'<group>' +
'<field name="bar" widget="boolean_favorite" />' +
'</group>' +
'</sheet>' +
'</form>',
res_id: 1,
});
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
'should be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
'the label should say "Remove from Favorites"');
// click on favorite
form.$('.o_field_widget.o_favorite').click();
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 0,
'should not be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites',
'the label should say "Add to Favorites"');
// switch to edit mode
form.$buttons.find('.o_form_button_edit').click();
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star-o').length, 1,
'should not be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites',
'the label should say "Add to Favorites"');
// click on favorite
form.$('.o_field_widget.o_favorite').click();
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
'should be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
'the label should say "Remove from Favorites"');
// save
form.$buttons.find('.o_form_button_save').click();
assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
'should be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
'the label should say "Remove from Favorites"');
form.destroy();
});
QUnit.test('favorite widget in editable list view without label', function (assert) {
assert.expect(4);
var list = createView({
View: ListView,
model: 'partner',
data: this.data,
arch: '<tree editable="bottom">' +
'<field name="bar" widget="boolean_favorite" nolabel="1" />' +
'</tree>',
});
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
'should be favorite');
// switch to edit mode
list.$('tbody td:not(.o_list_record_selector)').first().click();
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 1,
'should be favorite');
// click on favorite
list.$('.o_data_row:first .o_field_widget.o_favorite').click();
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 0,
'should not be favorite');
// save
list.$buttons.find('.o_list_button_save').click();
assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star-o').length, 1,
'should not be favorite');
list.destroy();
});
QUnit.module('LabelSelectionWidget');
QUnit.test('label_selection widget in form view', function (assert) {