[REF] marketing apps: better use toggle_active

Purpose of this merge is to call toggle_active or archive / unarchive methods
instead of manually writing on active field. Indeed this allows to trigger
business code related to archive / unarchive which is normally located
in toggle_archive (called by action_archive and action_unarchive).

We also improve some active-related behavior, notably

  * correctly cascade channel archive status to its slides;
  * cascade survey archive status to its certification badge;
  * fix opportunity lost / activated subtype in crm;

See sub commits for more details.

Task ID 2170708
Community PR #46563

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2020-04-03 15:28:07 +02:00
committed by GitHub
12 changed files with 68 additions and 32 deletions
+18 -5
View File
@@ -486,8 +486,17 @@ class Lead(models.Model):
# ------------------------------------------------------------
def toggle_active(self):
""" When archiving: mark probability as 0. When re-activating
update probability again, for leads and opportunities. """
res = super(Lead, self).toggle_active()
self.filtered(lambda lead: lead.active)._update_probability()
activated = self.filtered(lambda lead: lead.active)
archived = self.filtered(lambda lead: not lead.active)
if activated:
activated.write({'lost_reason': False})
activated._update_probability()
if archived:
archived.write({'probability': 0, 'automated_probability': 0})
archived._rebuild_pls_frequency_table_threshold()
return res
def _rebuild_pls_frequency_table_threshold(self):
@@ -506,12 +515,14 @@ class Lead(models.Model):
def action_set_lost(self, **additional_values):
""" Lost semantic: probability = 0 or active = False """
result = self.write({'active': False, 'probability': 0, 'automated_probability': 0, **additional_values})
self._rebuild_pls_frequency_table_threshold()
return result
res = self.action_archive()
if additional_values:
self.write(dict(additional_values))
return res
def action_set_won(self):
""" Won semantic: probability = 100 (active untouched) """
self.action_unarchive()
for lead in self:
stage_id = lead._stage_find(domain=[('is_won', '=', True)])
lead.write({'stage_id': stage_id.id, 'probability': 100})
@@ -1039,12 +1050,14 @@ class Lead(models.Model):
self.ensure_one()
if 'stage_id' in init_values and self.probability == 100 and self.stage_id:
return self.env.ref('crm.mt_lead_won')
elif 'lost_reason' in init_values:
elif 'lost_reason' in init_values and self.lost_reason:
return self.env.ref('crm.mt_lead_lost')
elif 'stage_id' in init_values:
return self.env.ref('crm.mt_lead_stage')
elif 'active' in init_values and self.active:
return self.env.ref('crm.mt_lead_restored')
elif 'active' in init_values and not self.active:
return self.env.ref('crm.mt_lead_lost')
return super(Lead, self)._track_subtype(init_values)
def _notify_get_groups(self):
+1 -2
View File
@@ -125,8 +125,7 @@ class Lead2OpportunityPartner(models.TransientModel):
def _action_merge(self):
to_merge = self.duplicated_lead_ids
result_opportunity = to_merge.merge_opportunity(auto_unlink=False)
if not result_opportunity.active:
result_opportunity.write({'active': True, 'lost_reason': False})
result_opportunity.action_unarchive()
if result_opportunity.type == "lead":
self._convert_and_allocate(result_opportunity, [self.user_id.id], team_id=self.team_id.id)
+2 -2
View File
@@ -73,7 +73,7 @@ class MailBlackList(models.Model):
normalized = tools.email_normalize(email)
record = self.env["mail.blacklist"].with_context(active_test=False).search([('email', '=', normalized)])
if len(record) > 0:
record.write({'active': True})
record.action_unarchive()
else:
record = self.create({'email': email})
return record
@@ -89,7 +89,7 @@ class MailBlackList(models.Model):
normalized = tools.email_normalize(email)
record = self.env["mail.blacklist"].with_context(active_test=False).search([('email', '=', normalized)])
if len(record) > 0:
record.write({'active': False})
record.action_archive()
else:
record = record.create({'email': email, 'active': False})
return record
+1 -1
View File
@@ -129,7 +129,7 @@ class MassMailingList(models.Model):
self.flush()
self.invalidate_cache()
if archive:
(src_lists - self).write({'active': False})
(src_lists - self).action_archive()
def close_dialog(self):
return {'type': 'ir.actions.act_window_close'}
@@ -89,7 +89,7 @@ class PhoneBlackList(models.Model):
records = self.env["phone.blacklist"].with_context(active_test=False).search([('number', 'in', numbers)])
todo = [n for n in numbers if n not in records.mapped('number')]
if records:
records.write({'active': True})
records.action_unarchive()
if todo:
records += self.create([{'number': n} for n in todo])
return records
@@ -112,7 +112,7 @@ class PhoneBlackList(models.Model):
records = self.env["phone.blacklist"].with_context(active_test=False).search([('number', 'in', numbers)])
todo = [n for n in numbers if n not in records.mapped('number')]
if records:
records.write({'active': False})
records.action_archive()
if todo:
records += self.create([{'number': n, 'active': False} for n in todo])
return records
+10 -4
View File
@@ -328,6 +328,12 @@ class Survey(models.Model):
default = dict(default or {}, title=title)
return super(Survey, self).copy_data(default)
def toggle_active(self):
super(Survey, self).toggle_active()
activated = self.filtered(lambda survey: survey.active)
activated.mapped('certification_badge_id').action_unarchive()
(self - activated).mapped('certification_badge_id').action_archive()
# ------------------------------------------------------------
# ANSWER MANAGEMENT
# ------------------------------------------------------------
@@ -946,6 +952,7 @@ class Survey(models.Model):
# ------------------------------------------------------------
# GAMIFICATION / BADGES
# ------------------------------------------------------------
def _prepare_challenge_category(self):
return 'certification'
@@ -983,9 +990,8 @@ class Survey(models.Model):
def _handle_certification_badges(self, vals):
if vals.get('certification_give_badge'):
# If badge already set on records, reactivate the ones that are not active.
surveys_with_badge = self.filtered(lambda survey: survey.certification_badge_id
and not survey.certification_badge_id.active)
surveys_with_badge.mapped('certification_badge_id').write({'active': True})
surveys_with_badge = self.filtered(lambda survey: survey.certification_badge_id and not survey.certification_badge_id.active)
surveys_with_badge.mapped('certification_badge_id').action_unarchive()
# (re-)create challenge and goal
for survey in self:
survey._create_certification_badge_trigger()
@@ -994,7 +1000,7 @@ class Survey(models.Model):
badges = self.mapped('certification_badge_id')
challenges_to_delete = self.env['gamification.challenge'].search([('reward_id', 'in', badges.ids)])
goals_to_delete = challenges_to_delete.mapped('line_ids').mapped('definition_id')
badges.write({'active': False})
badges.action_archive()
# delete all challenges and goals because not needed anymore (challenge lines are deleted in cascade)
challenges_to_delete.unlink()
goals_to_delete.unlink()
@@ -8,6 +8,7 @@ from odoo.tools import mute_logger
class TestCertificationBadge(common.TestSurveyCommon):
def setUp(self):
super(TestCertificationBadge, self).setUp()
self.certification_survey = self.env['survey.survey'].with_user(self.survey_manager).create({
@@ -49,6 +50,21 @@ class TestCertificationBadge(common.TestSurveyCommon):
'level': None,
})
def test_archive(self):
""" Archive status of survey is propagated to its badges. """
self.certification_survey.write({
'certification_give_badge': True,
'certification_badge_id': self.certification_badge.id
})
self.certification_survey.action_archive()
self.assertFalse(self.certification_survey.active)
self.assertFalse(self.certification_badge.active)
self.certification_survey.action_unarchive()
self.assertTrue(self.certification_survey.active)
self.assertTrue(self.certification_badge.active)
def test_give_badge_without_badge(self):
with mute_logger('odoo.sql_db'):
with self.assertRaises(IntegrityError):
+1 -1
View File
@@ -301,7 +301,7 @@ class Website(Home):
@http.route('/website/toggle_switchable_view', type='json', auth='user', website=True)
def toggle_switchable_view(self, view_key):
request.website.viewref(view_key).toggle()
request.website.viewref(view_key).toggle_active()
@http.route('/website/reset_template', type='http', auth='user', methods=['POST'], website=True, csrf=False)
def reset_template(self, view_id, mode='soft', redirect='/', **kwargs):
+12 -4
View File
@@ -87,7 +87,7 @@ class Channel(models.Model):
# description
name = fields.Char('Name', translate=True, required=True)
active = fields.Boolean(default=True)
active = fields.Boolean(default=True, tracking=100)
description = fields.Text('Description', translate=True, help="The description that is displayed on top of the course page, just below the title")
description_short = fields.Text('Short Description', translate=True, help="The description that is displayed on the course card")
description_html = fields.Html('Detailed Description', translate=tools.html_translate, sanitize_attributes=False, sanitize_form=False)
@@ -391,14 +391,22 @@ class Channel(models.Model):
if vals.get('user_id'):
self._action_add_members(self.env['res.users'].sudo().browse(vals['user_id']).partner_id)
if 'active' in vals:
# archiving/unarchiving a channel does it on its slides, too
self.with_context(active_test=False).mapped('slide_ids').write({'active': vals['active']})
if 'enroll_group_ids' in vals:
self._add_groups_members()
return res
def toggle_active(self):
# archiving/unarchiving a channel does it on its slides, too
to_archive = self.filtered(lambda channel: channel.active)
to_activate = self.filtered(lambda channel: not channel.active)
res = super(Channel, self).toggle_active()
if to_archive:
to_archive.mapped('slide_ids').action_archive()
if to_activate:
to_activate.with_context(active_test=False).mapped('slide_ids').action_unarchive()
return res
@api.returns('mail.message', lambda value: value.id)
def message_post(self, *, parent_id=False, subtype_id=False, **kwargs):
""" Temporary workaround to avoid spam. If someone replies on a channel
+2 -2
View File
@@ -127,7 +127,7 @@ class Slide(models.Model):
# description
name = fields.Char('Title', required=True, translate=True)
active = fields.Boolean(default=True)
active = fields.Boolean(default=True, tracking=100)
sequence = fields.Integer('Sequence', default=0)
user_id = fields.Many2one('res.users', string='Uploaded by', default=lambda self: self.env.uid)
description = fields.Text('Description', translate=True)
@@ -175,7 +175,7 @@ class Slide(models.Model):
html_content = fields.Html("HTML Content", help="Custom HTML content for slides of type 'Web Page'.", translate=True, sanitize_form=False)
# website
website_id = fields.Many2one(related='channel_id.website_id', readonly=True)
date_published = fields.Datetime('Publish Date', readonly=True, tracking=True)
date_published = fields.Datetime('Publish Date', readonly=True, tracking=1)
likes = fields.Integer('Likes', compute='_compute_user_info', store=True, compute_sudo=False)
dislikes = fields.Integer('Dislikes', compute='_compute_user_info', store=True, compute_sudo=False)
user_vote = fields.Integer('User vote', compute='_compute_user_info', compute_sudo=False)
-6
View File
@@ -511,12 +511,6 @@ actual arch.
default = dict(default or {}, key=new_key)
return super(View, self).copy(default)
def toggle(self):
""" Switches between enabled and disabled statuses
"""
for view in self:
view.write({'active': not view.active})
# default view selection
@api.model
def default_view(self, model, view_type):
+3 -3
View File
@@ -2634,7 +2634,7 @@ class TestOptionalViews(ViewCase):
""" Change active states of v2 and v3, check that the results
are as expected
"""
self.v2.toggle()
self.v2.toggle_active()
context = {'check_view_ids': self.View.search([]).ids}
arch = self.v0.with_context(context).read_combined(['arch'])['arch']
self.assertEqual(
@@ -2645,7 +2645,7 @@ class TestOptionalViews(ViewCase):
)
)
self.v3.toggle()
self.v3.toggle_active()
context = {'check_view_ids': self.View.search([]).ids}
arch = self.v0.with_context(context).read_combined(['arch'])['arch']
self.assertEqual(
@@ -2657,7 +2657,7 @@ class TestOptionalViews(ViewCase):
)
)
self.v2.toggle()
self.v2.toggle_active()
context = {'check_view_ids': self.View.search([]).ids}
arch = self.v0.with_context(context).read_combined(['arch'])['arch']
self.assertEqual(