[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:
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user