diff --git a/addons/im_livechat/data/im_livechat_channel_demo.xml b/addons/im_livechat/data/im_livechat_channel_demo.xml
index e6cde7dbfa6..5e3ca7fc937 100644
--- a/addons/im_livechat/data/im_livechat_channel_demo.xml
+++ b/addons/im_livechat/data/im_livechat_channel_demo.xml
@@ -31,7 +31,7 @@
-
-
+
+
|
-
-
+
+
|
diff --git a/addons/project/models/project.py b/addons/project/models/project.py
index 8accaa81de7..cc90d132df1 100644
--- a/addons/project/models/project.py
+++ b/addons/project/models/project.py
@@ -51,6 +51,7 @@ class ProjectTaskType(models.Model):
" * A good feedback from the customer will update the kanban state to 'ready for the new stage' (green bullet).\n"
" * A medium or a bad feedback will set the kanban state to 'blocked' (red bullet).\n")
is_closed = fields.Boolean('Closing Stage', help="Tasks in this stage are considered as closed.")
+ disabled_rating_warning = fields.Text(compute='_compute_disabled_rating_warning')
def unlink_wizard(self, stage_view=False):
self = self.with_context(active_test=False)
@@ -82,6 +83,15 @@ class ProjectTaskType(models.Model):
self.env['project.task'].search([('stage_id', 'in', self.ids)]).write({'active': False})
return super(ProjectTaskType, self).write(vals)
+ @api.depends('project_ids', 'project_ids.rating_active')
+ def _compute_disabled_rating_warning(self):
+ for stage in self:
+ disabled_projects = stage.project_ids.filtered(lambda p: not p.rating_active)
+ if disabled_projects:
+ stage.disabled_rating_warning = '\n'.join('- %s' % p.name for p in disabled_projects)
+ else:
+ stage.disabled_rating_warning = False
+
class Project(models.Model):
_name = "project.project"
@@ -172,11 +182,6 @@ class Project(models.Model):
def _get_default_favorite_user_ids(self):
return [(6, 0, [self.env.uid])]
- def _get_default_rating_status(self):
- if self.user_has_groups('project.group_project_rating'):
- return 'stage'
- return 'no'
-
name = fields.Char("Name", index=True, required=True, tracking=True)
active = fields.Boolean(default=True,
help="If the active field is set to False, it will allow you to hide the project without removing it.")
@@ -238,20 +243,22 @@ class Project(models.Model):
# rating fields
rating_request_deadline = fields.Datetime(compute='_compute_rating_request_deadline', store=True)
- rating_status = fields.Selection([
- ('stage', 'Rating when changing stage'),
- ('periodic', 'Periodical Rating'),
- ('no', 'No rating')], string='Customer Ratings', default=_get_default_rating_status, required=True,
+ rating_active = fields.Boolean('Customer Ratings', default=True)
+ rating_status = fields.Selection(
+ [('stage', 'Rating when changing stage'),
+ ('periodic', 'Periodical Rating')
+ ], 'Customer Ratings Status', default="stage", required=True,
help="How to get customer feedback?\n"
- "- Rating when changing stage: an email will be sent when a task is pulled in another stage.\n"
- "- Periodical Rating: email will be sent periodically.\n\n"
- "Don't forget to set up the mail templates on the stages for which you want to get the customer's feedbacks.")
+ "- Rating when changing stage: an email will be sent when a task is pulled in another stage.\n"
+ "- Periodical Rating: email will be sent periodically.\n\n"
+ "Don't forget to set up the mail templates on the stages for which you want to get the customer's feedbacks.")
rating_status_period = fields.Selection([
- ('daily', 'Daily'), ('weekly', 'Weekly'), ('bimonthly', 'Twice a Month'),
- ('monthly', 'Once a Month'), ('quarterly', 'Quarterly'), ('yearly', 'Yearly')
- ], 'Rating Frequency')
-
- portal_show_rating = fields.Boolean('Rating visible publicly', copy=False)
+ ('daily', 'Daily'),
+ ('weekly', 'Weekly'),
+ ('bimonthly', 'Twice a Month'),
+ ('monthly', 'Once a Month'),
+ ('quarterly', 'Quarterly'),
+ ('yearly', 'Yearly')], 'Rating Frequency', required=True, default='monthly')
_sql_constraints = [
('project_date_greater', 'check(date >= date_start)', 'Error! project start-date must be lower than project end-date.')
@@ -452,14 +459,7 @@ class Project(models.Model):
return action
def action_view_all_rating(self):
- """ return the action to see all the rating of the project, and activate default filters """
- if self.portal_show_rating:
- return {
- 'type': 'ir.actions.act_url',
- 'name': "Redirect to the Website Projcet Rating Page",
- 'target': 'self',
- 'url': "/project/rating/%s" % (self.id,)
- }
+ """ return the action to see all the rating of the project and activate default filters"""
action = self.env['ir.actions.act_window'].for_xml_id('project', 'rating_rating_action_view_project_rating')
action['name'] = _('Ratings of %s') % (self.name,)
action_context = ast.literal_eval(action['context']) if action['context'] else {}
diff --git a/addons/project/models/res_config_settings.py b/addons/project/models/res_config_settings.py
index 439e09d7705..e63c53edc59 100644
--- a/addons/project/models/res_config_settings.py
+++ b/addons/project/models/res_config_settings.py
@@ -10,18 +10,4 @@ class ResConfigSettings(models.TransientModel):
module_project_forecast = fields.Boolean(string="Planning")
module_hr_timesheet = fields.Boolean(string="Task Logs")
group_subtask_project = fields.Boolean("Sub-tasks", implied_group="project.group_subtask_project")
- group_project_rating = fields.Boolean("Use Rating on Project", implied_group='project.group_project_rating')
-
- def _get_subtasks_projects_domain(self):
- return []
-
- def execute(self):
- res = super(ResConfigSettings, self).execute()
- if self.group_project_rating:
- # Change the rating status on existing projects from 'no' to 'stage'
- self.env['project.project'].search([('rating_status', '=', 'no')]).write({
- 'rating_status': 'stage'})
- if self.group_subtask_project:
- domain = self._get_subtasks_projects_domain()
- self.env['project.project'].search(domain).write({'allow_subtasks': True})
- return res
+ group_project_rating = fields.Boolean("Customer Ratings", implied_group='project.group_project_rating')
diff --git a/addons/project/tests/test_project_flow.py b/addons/project/tests/test_project_flow.py
index 5f1d8e3400c..fdb5450e12a 100644
--- a/addons/project/tests/test_project_flow.py
+++ b/addons/project/tests/test_project_flow.py
@@ -142,7 +142,7 @@ class TestProjectFlow(TestProjectCommon):
'parent_res_id': self.project_pigs.id,
'rated_partner_id': self.partner_2.id,
'partner_id': self.partner_2.id,
- 'rating': 10,
+ 'rating': 5,
'consumed': False,
})
@@ -153,7 +153,7 @@ class TestProjectFlow(TestProjectCommon):
'parent_res_id': self.project_pigs.id,
'rated_partner_id': self.partner_2.id,
'partner_id': self.partner_2.id,
- 'rating': 5,
+ 'rating': 3,
'consumed': True,
})
@@ -170,7 +170,7 @@ class TestProjectFlow(TestProjectCommon):
self.assertEqual(self.project_pigs.rating_percentage_satisfaction, 0) # There is a rating but not a "great" on, just an "okay".
# Consuming rating_good
- first_task.rating_apply(10, rating_good.access_token)
+ first_task.rating_apply(5, rating_good.access_token)
# We need to invalidate cache since it is not done automatically by the ORM
# Our One2Many is linked to a res_id (int) for which the orm doesn't create an inverse
diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml
index 2fd2c4ef026..72a73474862 100644
--- a/addons/project/views/project_views.xml
+++ b/addons/project/views/project_views.xml
@@ -89,6 +89,161 @@
+
+
+
+
+
+
+
+ + + Create a new stage in the task pipeline + + Define the steps that will be used in the project from the + creation of the task, up to the closing of the task or issue. + You will use these stages in order to track the progress in + solving a task or an issue. + ++ Create a new stage in the task pipeline + + Define the steps that will be used in the project from the + creation of the task, up to the closing of the task or issue. + You will use these stages in order to track the progress in + solving a task or an issue. + +
@@ -151,23 +307,24 @@
+
+
-
+
diff --git a/addons/rating/controllers/main.py b/addons/rating/controllers/main.py
index 5c1f7f5f4ce..e27fc6b7c53 100644
--- a/addons/rating/controllers/main.py
+++ b/addons/rating/controllers/main.py
@@ -11,13 +11,13 @@ class Rating(http.Controller):
@http.route('/rating/
Get customer feedback
-
-
- Edit project's stages and set an email template on the stages on which you want to activate the rating. - +
+
@@ -352,6 +509,7 @@
-
-
-
-
+
+
- Customer Ratings
-
-
-
-
-
-
- - - Create a new stage in the task pipeline - - Define the steps that will be used in the project from the - creation of the task, up to the closing of the task or issue. - You will use these stages in order to track the progress in - solving a task or an issue. - -- There are no ratings for this object at the moment + There are no ratings for this project at the moment
-
-
+
@@ -95,7 +95,7 @@
-
+
@@ -131,7 +131,7 @@
-
-
diff --git a/addons/website_project/__init__.py b/addons/website_project/__init__.py
new file mode 100644
index 00000000000..7d34c7c054a
--- /dev/null
+++ b/addons/website_project/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import controllers
+from . import models
diff --git a/addons/website_project/__manifest__.py b/addons/website_project/__manifest__.py
new file mode 100644
index 00000000000..cb467db65e6
--- /dev/null
+++ b/addons/website_project/__manifest__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Website Project',
+ 'category': 'Website/Website',
+ 'summary': 'Publish your project ratings',
+ 'version': '1.0',
+ 'description': """
+Allows to publish all ratings for a particular project.""",
+ 'depends': ['website', 'project'],
+ 'data': [
+ 'views/project_rating_templates.xml',
+ 'views/project_project_views.xml',
+ ],
+ 'installable': True,
+ 'auto_install': True,
+}
diff --git a/addons/website_project/controllers/__init__.py b/addons/website_project/controllers/__init__.py
new file mode 100644
index 00000000000..7367c6c8192
--- /dev/null
+++ b/addons/website_project/controllers/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import rating
diff --git a/addons/project/controllers/rating.py b/addons/website_project/controllers/rating.py
similarity index 85%
rename from addons/project/controllers/rating.py
rename to addons/website_project/controllers/rating.py
index c57734e6a99..7e0c3d5dda2 100644
--- a/addons/project/controllers/rating.py
+++ b/addons/website_project/controllers/rating.py
@@ -11,9 +11,11 @@ class RatingProject(http.Controller):
@http.route(['/project/rating'], type='http', auth="public", website=True, sitemap=True)
def index(self, **kw):
- projects = request.env['project.project'].sudo().search([('rating_status', '!=', 'no'), ('portal_show_rating', '=', True)])
+ projects = request.env['project.project'].sudo().search([
+ ('rating_active', '=', True),
+ ('is_published', '=', True)])
values = {'projects': projects}
- return request.render('project.rating_index', values)
+ return request.render('website_project.rating_index', values)
def _calculate_period_partner_stats(self, project_id):
# get raw data: number of rating by rated partner, by rating value, by period
@@ -36,7 +38,7 @@ class RatingProject(http.Controller):
AND res_model = 'project.task'
AND rated_partner_id IS NOT NULL
AND write_date >= current_date - interval '90' day
- AND rating IN (1,5,10)
+ AND rating IN (1, 3, 5)
GROUP BY
rated_partner_id, rating, period
""", (project_id, ))
@@ -44,7 +46,7 @@ class RatingProject(http.Controller):
raw_data = request.env.cr.dictfetchall()
# periodical statistics
- default_period_dict = {'rating_10': 0, 'rating_5': 0, 'rating_1': 0, 'total': 0}
+ default_period_dict = {'rating_5': 0, 'rating_3': 0, 'rating_1': 0, 'total': 0}
period_statistics = {
'days_06': dict(default_period_dict),
'days_15': dict(default_period_dict),
@@ -58,7 +60,7 @@ class RatingProject(http.Controller):
period_statistics[period_statistics_key]['total'] += row['rating_count']
# partner statistics
- default_partner_dict = {'rating_10': 0, 'rating_5': 0, 'rating_1': 0, 'total': 0, 'rated_partner': None, 'percentage_happy': 0.0}
+ default_partner_dict = {'rating_5': 0, 'rating_3': 0, 'rating_1': 0, 'total': 0, 'rated_partner': None, 'percentage_happy': 0.0}
partner_statistics = {}
for row in raw_data:
if row['period'] <= 'days_15':
@@ -69,7 +71,7 @@ class RatingProject(http.Controller):
partner_statistics[row['rated_partner_id']]['total'] += row['rating_count']
for partner_id, stat_values in partner_statistics.items():
- stat_values['percentage_happy'] = (stat_values['rating_10'] / float(stat_values['total'])) * 100 if stat_values['total'] else 0.0
+ stat_values['percentage_happy'] = (stat_values['rating_5'] / float(stat_values['total'])) * 100 if stat_values['total'] else 0.0
return {
'partner_statistics': partner_statistics,
@@ -82,10 +84,10 @@ class RatingProject(http.Controller):
project = request.env['project.project'].sudo().browse(project_id)
# to avoid giving any access rights on projects to the public user, let's use sudo
# and check if the user should be able to view the project (project managers only if it's unpublished or has no rating)
- if not ((project.rating_status != 'no') and project.portal_show_rating) and not user.with_user(user).has_group('project.group_project_manager'):
+ if not (project.rating_active and project.is_published) and not user.with_user(user).has_group('project.group_project_manager'):
raise NotFound()
- return request.render('project.rating_project_rating_page', {
+ return request.render('website_project.rating_project_rating_page', {
'project': project,
'ratings': request.env['rating.rating'].sudo().search([
('consumed', '=', True),
diff --git a/addons/website_project/models/__init__.py b/addons/website_project/models/__init__.py
new file mode 100644
index 00000000000..527e2954c06
--- /dev/null
+++ b/addons/website_project/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import project
diff --git a/addons/website_project/models/project.py b/addons/website_project/models/project.py
new file mode 100644
index 00000000000..ded92b699a2
--- /dev/null
+++ b/addons/website_project/models/project.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+
+
+class Project(models.Model):
+ _name = 'project.project'
+ _inherit = ['project.project', 'website.published.mixin']
+
+ def action_view_all_rating(self):
+ if self.website_published:
+ return self.open_website_url()
+ return super(Project, self).action_view_all_rating()
+
+ def open_website_url(self):
+ """ return the action to see all the rating of the project, and activate default filters """
+ return {
+ 'type': 'ir.actions.act_url',
+ 'name': "Redirect to the Website Project Rating Page",
+ 'target': 'self',
+ 'url': "/project/rating/%s" % (self.id)
+ }
diff --git a/addons/website_project/views/project_project_views.xml b/addons/website_project/views/project_project_views.xml
new file mode 100644
index 00000000000..354adc30d5b
--- /dev/null
+++ b/addons/website_project/views/project_project_views.xml
@@ -0,0 +1,16 @@
+
+
-
-
+
+
-
+ |