diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py index 3f26e16414f..96d85673011 100644 --- a/addons/website_slides/models/slide_channel.py +++ b/addons/website_slides/models/slide_channel.py @@ -34,6 +34,7 @@ class ChannelUsersRelation(models.Model): channel_visibility = fields.Selection(related='channel_id.visibility') channel_enroll = fields.Selection(related='channel_id.enroll') channel_website_id = fields.Many2one('website', string='Website', related='channel_id.website_id') + next_slide_id = fields.Many2one('slide.slide', string='Next Lesson', compute='_compute_next_slide_id') _sql_constraints = [ ('channel_partner_uniq', @@ -46,6 +47,39 @@ class ChannelUsersRelation(models.Model): ) ] + def _compute_next_slide_id(self): + self.env['slide.channel.partner'].flush_model() + self.env['slide.slide'].flush_model() + self.env['slide.slide.partner'].flush_model() + query = """ + SELECT DISTINCT ON (SCP.id) + SCP.id AS id, + SS.id AS slide_id + FROM slide_channel_partner SCP + JOIN slide_slide SS + ON SS.channel_id = SCP.channel_id + AND SS.is_published = TRUE + AND SS.active = TRUE + AND SS.is_category = FALSE + AND NOT EXISTS ( + SELECT 1 + FROM slide_slide_partner + WHERE slide_id = SS.id + AND partner_id = SCP.partner_id + AND completed = TRUE + ) + WHERE SCP.id IN %s + ORDER BY SCP.id, SS.sequence, SS.id + """ + self.env.cr.execute(query, [tuple(self.ids)]) + next_slide_per_membership = { + line['id']: line['slide_id'] + for line in self.env.cr.dictfetchall() + } + + for membership in self: + membership.next_slide_id = next_slide_per_membership.get(membership.id, False) + def _recompute_completion(self): read_group_res = self.env['slide.slide.partner'].sudo()._read_group( ['&', '&', ('channel_id', 'in', self.mapped('channel_id').ids), diff --git a/addons/website_slides/tests/test_slide_channel.py b/addons/website_slides/tests/test_slide_channel.py index 8fe333653cb..b140354920a 100644 --- a/addons/website_slides/tests/test_slide_channel.py +++ b/addons/website_slides/tests/test_slide_channel.py @@ -53,6 +53,73 @@ class TestSlidesManagement(slides_common.SlidesCase): else: self.assertTrue(slide.is_published, "All slides should be unpublished when a channel is archived, except categories") + @users('user_manager') + def test_channel_partner_next_slide(self): + """ Test the mechanic of the 'next_slide' field for memberships. + Next slide should be equal to the next slide in order (sequence, id) based on completion. """ + + channel = self.env['slide.channel'].create({ + 'name': 'Channel1', + 'channel_type': 'documentation', + 'enroll': 'public', + 'visibility': 'public', + 'is_published': True, + }) + + category_1, category_2 = self.env['slide.slide'].create([{ + 'name': 'Category %s' % i, + 'channel_id': channel.id, + 'is_category': True, + 'is_published': True, + } for i in [1, 2]]) + + # create 2 slides within the first category + slide_1, slide_2 = self.env['slide.slide'].create([{ + 'name': 'slide %s' % i, + 'channel_id': channel.id, + 'category_id': category_1.id, + 'slide_category': 'document', + 'is_published': True, + } for i in [1, 2]]) + + # create 2 slides within the second category + slide_3, slide_4 = self.env['slide.slide'].create([{ + 'name': 'slide %s' % i, + 'channel_id': channel.id, + 'category_id': category_2.id, + 'slide_category': 'document', + 'is_published': True, + } for i in [3, 4]]) + + self.assertEqual(channel.slide_content_ids, slide_1 | slide_2 | slide_3 | slide_4) + # test the behavior on both employees and portal users + users = self.user_emp | self.user_portal + channel.sudo()._action_add_members(users.partner_id) + memberships = self.env['slide.channel.partner'].sudo().search([('partner_id', 'in', users.partner_id.ids)]) + + for membership in memberships: + for slide in channel.slide_content_ids: + self.assertEqual( + membership.next_slide_id, + slide, + 'Expected %(expected_slide)s but got %(actual_slide)s' % { + 'expected_slide': slide.name, + 'actual_slide': membership.next_slide_id.name, + } + ) + + self.env['slide.slide.partner'].create({ + 'slide_id': slide.id, + 'channel_id': channel.id, + 'partner_id': membership.partner_id.id, + 'completed': True + }) + + membership.invalidate_recordset(fnames=['next_slide_id']) + + # we have gone through all the content, next slide should be False + self.assertFalse(membership.next_slide_id) + def test_mail_completed(self): """ When the slide.channel is completed, an email is supposed to be sent to people that completed it. """ channel_2 = self.env['slide.channel'].create({ diff --git a/addons/website_slides/views/slide_channel_partner_views.xml b/addons/website_slides/views/slide_channel_partner_views.xml index 6a91c424f67..ed53bf7af1a 100644 --- a/addons/website_slides/views/slide_channel_partner_views.xml +++ b/addons/website_slides/views/slide_channel_partner_views.xml @@ -31,6 +31,7 @@ + + @@ -190,8 +191,12 @@ - + + + + +