From dbca47129c9c6042c62494b88fcd50aba4a716ca Mon Sep 17 00:00:00 2001 From: lreficent Date: Fri, 1 Dec 2017 16:56:35 -0500 Subject: [PATCH 001/210] [9.0][ADD] base_tier_validation --- base_tier_validation/README.rst | 73 ++++++++++ base_tier_validation/__init__.py | 4 + base_tier_validation/__openerp__.py | 22 +++ base_tier_validation/models/__init__.py | 6 + .../models/tier_definition.py | 54 +++++++ base_tier_validation/models/tier_review.py | 41 ++++++ .../models/tier_validation.py | 134 ++++++++++++++++++ .../security/ir.model.access.csv | 4 + .../views/tier_definition_view.xml | 61 ++++++++ .../views/tier_review_view.xml | 22 +++ 10 files changed, 421 insertions(+) create mode 100644 base_tier_validation/README.rst create mode 100644 base_tier_validation/__init__.py create mode 100644 base_tier_validation/__openerp__.py create mode 100644 base_tier_validation/models/__init__.py create mode 100644 base_tier_validation/models/tier_definition.py create mode 100644 base_tier_validation/models/tier_review.py create mode 100644 base_tier_validation/models/tier_validation.py create mode 100644 base_tier_validation/security/ir.model.access.csv create mode 100644 base_tier_validation/views/tier_definition_view.xml create mode 100644 base_tier_validation/views/tier_review_view.xml diff --git a/base_tier_validation/README.rst b/base_tier_validation/README.rst new file mode 100644 index 0000000000..8e27d1d467 --- /dev/null +++ b/base_tier_validation/README.rst @@ -0,0 +1,73 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: https://www.gnu.org/licenses/agpl + :alt: License: AGPL-3 + +==================== +Base Tier Validation +==================== + +This module does not provide a functionality by itself but an abstract model +to implement a validation process based on tiers on other models (e.g. +purchase orders, sales orders...). + +**Note:** To be able to use this module in a new model you will need some +development. + +See `purchase_tier_validation `_ as an example of implementation. + +Configuration +============= + +To configure this module, you need to: + +#. Go to *Settings > Technical > Tier Validations > Tier Definition*. +#. Create as many tiers as you want for any model having tier validation + functionality. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/149/9.0 + +Known issues / Roadmap +====================== + +* In odoo v11 it would be interesting to try to take advantage of ``mail.activity.mixin``. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Lois Rilo + +Do not contact contributors directly about support or help with technical issues. + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/base_tier_validation/__init__.py b/base_tier_validation/__init__.py new file mode 100644 index 0000000000..b44d765940 --- /dev/null +++ b/base_tier_validation/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/base_tier_validation/__openerp__.py b/base_tier_validation/__openerp__.py new file mode 100644 index 0000000000..ce34496eca --- /dev/null +++ b/base_tier_validation/__openerp__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Base Tier Validation", + "summary": "Implement a validation process based on tiers.", + "version": "9.0.1.0.0", + "category": "Tools", + "website": "https://github.com/OCA/server-tools", + "author": "Eficent, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "base", + ], + "data": [ + "security/ir.model.access.csv", + "views/tier_definition_view.xml", + "views/tier_review_view.xml", + ], +} diff --git a/base_tier_validation/models/__init__.py b/base_tier_validation/models/__init__.py new file mode 100644 index 0000000000..d7c418aa8f --- /dev/null +++ b/base_tier_validation/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import tier_definition +from . import tier_review +from . import tier_validation diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py new file mode 100644 index 0000000000..ffa81446ef --- /dev/null +++ b/base_tier_validation/models/tier_definition.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + + +class TierDefinition(models.Model): + _name = "tier.definition" + _rec_name = "model_id" + + @api.model + def _get_tier_validation_model_names(self): + res = [] + return res + + model_id = fields.Many2one( + comodel_name="ir.model", + string="Referenced Model", + ) + model = fields.Char( + related='model_id.model', index=True, store=True, + ) + review_type = fields.Selection( + string="Validated by", default="individual", + selection=[("individual", "Specific user"), + ("group", "Any user in a specific group.")] + ) + reviewer_id = fields.Many2one( + comodel_name="res.users", string="Reviewer", + ) + reviewer_group_id = fields.Many2one( + comodel_name="res.groups", string="Reviewer group", + ) + python_code = fields.Text( + string='Tier Definition Expression', + help="Write Python code that defines when this tier confirmation " + "will be needed. The result of executing the expresion must be " + "a boolean.", + default="""# Available locals:\n# - rec: current record""", + ) + active = fields.Boolean(default=True) + sequence = fields.Integer(default=30) + company_id = fields.Many2one( + comodel_name="res.company", string="Company", + default=lambda self: self.env["res.company"]._company_default_get( + "tier.definition"), + ) + + @api.onchange('model_id') + def onchange_model_id(self): + return {'domain': { + 'model_id': [ + ('model', 'in', self._get_tier_validation_model_names())]}} diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py new file mode 100644 index 0000000000..e7afe7a728 --- /dev/null +++ b/base_tier_validation/models/tier_review.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + + +class TierReview(models.Model): + _name = "tier.review" + + status = fields.Selection( + selection=[("pending", "Pending"), + ("rejected", "Rejected"), + ("approved", "Approved")], + default="pending", + ) + model = fields.Char(string='Related Document Model', index=True) + res_id = fields.Integer(string='Related Document ID', index=True) + definition_id = fields.Many2one( + comodel_name="tier.definition", + ) + review_type = fields.Selection( + related="definition_id.review_type", readonly=True, + ) + reviewer_id = fields.Many2one( + related="definition_id.reviewer_id", readonly=True, + ) + reviewer_group_id = fields.Many2one( + related="definition_id.reviewer_group_id", readonly=True, + ) + reviewer_ids = fields.Many2many( + string="Reviewers", comodel_name="res.users", + compute="_compute_reviewer_ids", store=True, + ) + sequence = fields.Integer(string="Tier") + + @api.multi + @api.depends('reviewer_id', 'reviewer_group_id', 'reviewer_group_id.users') + def _compute_reviewer_ids(self): + for rec in self: + rec.reviewer_ids = rec.reviewer_id + rec.reviewer_group_id.users diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py new file mode 100644 index 0000000000..027ceffa79 --- /dev/null +++ b/base_tier_validation/models/tier_validation.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models, _ +from openerp.exceptions import ValidationError, UserError +from openerp.tools.safe_eval import safe_eval + + +class TierValidation(models.AbstractModel): + _name = "tier.validation" + + _state_field = 'state' + _state_from = ['draft'] + _state_to = ['confirmed'] + _cancel_state = 'cancel' + + # TODO: reset validation? + # TODO: step by step validation? + + review_ids = fields.One2many( + comodel_name='tier.review', inverse_name='res_id', + string='Validations', + domain=lambda self: [('model', '=', self._name)], + auto_join=True, + ) + validated = fields.Boolean(compute="_compute_validated_rejected") + need_validation = fields.Boolean(compute="_compute_need_validation") + rejected = fields.Boolean(compute="_compute_validated_rejected") + reviewer_ids = fields.Many2many( + string="Reviewers", comodel_name="res.users", + compute="_compute_reviewer_ids", + search="_search_reviewer_ids", + ) + + @api.multi + @api.depends('review_ids') + def _compute_reviewer_ids(self): + for rec in self: + rec.reviewer_ids = rec.review_ids.filtered( + lambda r: r.status == 'pending').mapped('reviewer_ids') + + @api.model + def _search_reviewer_ids(self, operator, value): + reviews = self.env['tier.review'].search([ + ('model', '=', self._name), ('reviewer_ids', operator, value)]) + return [('id', 'in', list(set(reviews.mapped('res_id'))))] + + @api.multi + def _compute_validated_rejected(self): + """Override for different validation/rejection policy.""" + for rec in self: + # sort by tier + rec.validated = not any( + [s != 'approved' for s in self.review_ids.mapped('status')]) + rec.rejected = any( + [s == 'rejected' for s in self.review_ids.mapped('status')]) + + @api.multi + def _compute_need_validation(self): + for rec in self: + rec.need_validation = not self.review_ids and self.env[ + 'tier.definition'].search([('model', '=', self._name)]) and \ + getattr(rec, self._state_field) in self._state_from + + @api.multi + def evaluate_tier(self, tier): + try: + res = safe_eval(tier.python_code, globals_dict={'rec': self}) + except Exception, error: + raise UserError(_( + "Error evaluating tier validation conditions.\n %s") % error) + return res + + @api.multi + def write(self, vals): + for rec in self: + if (getattr(rec, self._state_field) in self._state_from and + vals.get(self._state_field) in self._state_to): + if rec.need_validation: + raise ValidationError(_( + "This action needs to be validated for at least one " + "record. \nPlease request a validation.")) + if not rec.validated: + raise ValidationError(_( + "A validation process is still open for at least " + "one record.")) + if (rec.review_ids and getattr(rec, self._state_field) in + self._state_from and not vals.get(self._state_field) in + (self._state_to + [self._cancel_state])): + raise ValidationError(_("The operation is under validation.")) + if vals.get(self._state_field) in self._state_from: + self.mapped('review_ids').sudo().unlink() + return super(TierValidation, self).write(vals) + + @api.multi + def validate_tier(self): + for rec in self: + user_reviews = rec.review_ids.filtered( + lambda r: r.status in ('pending', 'rejected') and + (r.reviewer_id == self.env.user or + r.reviewer_group_id in self.env.user.groups_id)) + user_reviews.write({'status': 'approved'}) + + @api.multi + def reject_tier(self): + for rec in self: + user_reviews = rec.review_ids.filtered( + lambda r: r.status in ('pending', 'approved') and + (r.reviewer_id == self.env.user or + r.reviewer_group_id in self.env.user.groups_id)) + user_reviews.write({'status': 'rejected'}) + + @api.multi + def request_validation(self): + td_obj = self.env['tier.definition'] + tr_obj = self.env['tier.review'] + for rec in self: + if getattr(rec, self._state_field) in self._state_from: + if rec.need_validation: + tier_definitions = td_obj.search([ + ('model', '=', self._name)], order="sequence desc") + sequence = 0 + for td in tier_definitions: + if self.evaluate_tier(td): + sequence += 1 + tr_obj.create({ + 'model': self._name, + 'res_id': rec.id, + 'definition_id': td.id, + 'sequence': sequence, + }) + # TODO: notify? post some msg in chatter? + return True diff --git a/base_tier_validation/security/ir.model.access.csv b/base_tier_validation/security/ir.model.access.csv new file mode 100644 index 0000000000..849101732c --- /dev/null +++ b/base_tier_validation/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_tier_review,access.tier.review,model_tier_review,,1,1,1,1 +access_tier_definition_all,tier.definition.all,model_tier_definition,,1,0,0,0 +access_tier_definition_settings,tier.definition.settings,model_tier_definition,base.group_system,1,1,1,1 diff --git a/base_tier_validation/views/tier_definition_view.xml b/base_tier_validation/views/tier_definition_view.xml new file mode 100644 index 0000000000..5511b38b5d --- /dev/null +++ b/base_tier_validation/views/tier_definition_view.xml @@ -0,0 +1,61 @@ + + + + + + tier.definition.tree + tier.definition + + + + + + + + + + + + tier.definition.form + tier.definition + +
+ + + + + + + + + + + + + + + + +
+
+
+ + + Tier Definition + ir.actions.act_window + tier.definition + form + tree,form + + + + + +
diff --git a/base_tier_validation/views/tier_review_view.xml b/base_tier_validation/views/tier_review_view.xml new file mode 100644 index 0000000000..df0509f707 --- /dev/null +++ b/base_tier_validation/views/tier_review_view.xml @@ -0,0 +1,22 @@ + + + + + + tier.review.tree + tier.review + + + + + + + + + + + + From 6470c9cd0a60e7837d1378853da4ab4465ad637b Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Wed, 28 Feb 2018 18:20:06 +0100 Subject: [PATCH 002/210] fix: blocking unneded records --- base_tier_validation/models/tier_validation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 027ceffa79..baf5361545 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -59,8 +59,10 @@ def _compute_validated_rejected(self): @api.multi def _compute_need_validation(self): for rec in self: - rec.need_validation = not self.review_ids and self.env[ - 'tier.definition'].search([('model', '=', self._name)]) and \ + tiers = self.env[ + 'tier.definition'].search([('model', '=', self._name)]) + valid_tiers = any([self.evaluate_tier(tier) for tier in tiers]) + rec.need_validation = not self.review_ids and valid_tiers and \ getattr(rec, self._state_field) in self._state_from @api.multi From 67546faf5843481706a4f8bbafc474b8e61fbcde Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Fri, 2 Mar 2018 16:11:18 +0100 Subject: [PATCH 003/210] [9.0][IMP] base_tier_validation: tries automatically request validation and validate if possible. --- .../models/tier_validation.py | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index baf5361545..d08e90ee2e 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -48,13 +48,19 @@ def _search_reviewer_ids(self, operator, value): @api.multi def _compute_validated_rejected(self): - """Override for different validation/rejection policy.""" for rec in self: - # sort by tier - rec.validated = not any( - [s != 'approved' for s in self.review_ids.mapped('status')]) - rec.rejected = any( - [s == 'rejected' for s in self.review_ids.mapped('status')]) + rec.validated = self._calc_reviews_validated(rec.review_ids) + rec.rejected = self._calc_reviews_rejected(rec.review_ids) + + @api.model + def _calc_reviews_validated(self, reviews): + """Override for different validation policy.""" + return not any([s != 'approved' for s in reviews.mapped('status')]) + + @api.model + def _calc_reviews_rejected(self, reviews): + """Override for different rejection policy.""" + return any([s == 'rejected' for s in reviews.mapped('status')]) @api.multi def _compute_need_validation(self): @@ -80,9 +86,13 @@ def write(self, vals): if (getattr(rec, self._state_field) in self._state_from and vals.get(self._state_field) in self._state_to): if rec.need_validation: - raise ValidationError(_( - "This action needs to be validated for at least one " - "record. \nPlease request a validation.")) + # try to validate operation + reviews = rec.request_validation() + rec._validate_tier(reviews) + if not self._calc_reviews_validated(reviews): + raise ValidationError(_( + "This action needs to be validated for at least " + "one record. \nPlease request a validation.")) if not rec.validated: raise ValidationError(_( "A validation process is still open for at least " @@ -95,14 +105,19 @@ def write(self, vals): self.mapped('review_ids').sudo().unlink() return super(TierValidation, self).write(vals) + def _validate_tier(self, tiers=False): + self.ensure_one() + tier_reviews = tiers or self.review_ids + user_reviews = tier_reviews.filtered( + lambda r: r.status in ('pending', 'rejected') and + (r.reviewer_id == self.env.user or + r.reviewer_group_id in self.env.user.groups_id)) + user_reviews.write({'status': 'approved'}) + @api.multi def validate_tier(self): for rec in self: - user_reviews = rec.review_ids.filtered( - lambda r: r.status in ('pending', 'rejected') and - (r.reviewer_id == self.env.user or - r.reviewer_group_id in self.env.user.groups_id)) - user_reviews.write({'status': 'approved'}) + rec._validate_tier() @api.multi def reject_tier(self): @@ -116,7 +131,7 @@ def reject_tier(self): @api.multi def request_validation(self): td_obj = self.env['tier.definition'] - tr_obj = self.env['tier.review'] + tr_obj = created_trs = self.env['tier.review'] for rec in self: if getattr(rec, self._state_field) in self._state_from: if rec.need_validation: @@ -126,11 +141,11 @@ def request_validation(self): for td in tier_definitions: if self.evaluate_tier(td): sequence += 1 - tr_obj.create({ + created_trs += tr_obj.create({ 'model': self._name, 'res_id': rec.id, 'definition_id': td.id, 'sequence': sequence, }) # TODO: notify? post some msg in chatter? - return True + return created_trs From 967641930c38eb3d7a0daffc2eb0ce9a0046596e Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Fri, 2 Mar 2018 16:18:03 +0100 Subject: [PATCH 004/210] [9.0][IMP] base_tier_validation: filter out reviews not pending --- base_tier_validation/models/tier_validation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index d08e90ee2e..fc97f0909b 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -43,7 +43,9 @@ def _compute_reviewer_ids(self): @api.model def _search_reviewer_ids(self, operator, value): reviews = self.env['tier.review'].search([ - ('model', '=', self._name), ('reviewer_ids', operator, value)]) + ('model', '=', self._name), + ('reviewer_ids', operator, value), + ('status', '=', 'pending')]) return [('id', 'in', list(set(reviews.mapped('res_id'))))] @api.multi From ddb820e7da4e5b22fc005f96be5c029def6166b5 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Fri, 2 Mar 2018 16:39:09 +0100 Subject: [PATCH 005/210] make possible to filter by validated records --- base_tier_validation/models/tier_validation.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index fc97f0909b..ce9763d62a 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -24,7 +24,10 @@ class TierValidation(models.AbstractModel): domain=lambda self: [('model', '=', self._name)], auto_join=True, ) - validated = fields.Boolean(compute="_compute_validated_rejected") + validated = fields.Boolean( + compute="_compute_validated_rejected", + search="_search_validated", + ) need_validation = fields.Boolean(compute="_compute_need_validation") rejected = fields.Boolean(compute="_compute_validated_rejected") reviewer_ids = fields.Many2many( @@ -40,6 +43,15 @@ def _compute_reviewer_ids(self): rec.reviewer_ids = rec.review_ids.filtered( lambda r: r.status == 'pending').mapped('reviewer_ids') + @api.model + def _search_validated(self, operator, value): + assert operator in ('=', '!='), 'Invalid domain operator' + assert value in (True, False), 'Invalid domain value' + pos = self.search([ + (self._state_field, 'in', self._state_from)]).filtered( + lambda r: r.review_ids and r.validated == value) + return [('id', 'in', pos.ids)] + @api.model def _search_reviewer_ids(self, operator, value): reviews = self.env['tier.review'].search([ From 636761899511ae99c399ac8e091266f9ab7535ae Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Thu, 15 Mar 2018 12:17:19 +0100 Subject: [PATCH 006/210] allow to add exceptions for fields that can be written on under validation records --- base_tier_validation/models/tier_validation.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index ce9763d62a..e6cd55990e 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -94,6 +94,21 @@ def evaluate_tier(self, tier): "Error evaluating tier validation conditions.\n %s") % error) return res + @api.model + def _get_under_validation_exceptions(self): + """Extend for more field exceptions.""" + return ['message_follower_ids'] + + @api.multi + def _check_allow_write_under_validation(self, vals): + """Allow to add exceptions for fields that are allowed to be written + even when the record is under validation.""" + exceptions = self._get_under_validation_exceptions() + for val in vals: + if val not in exceptions: + return False + return True + @api.multi def write(self, vals): for rec in self: @@ -113,7 +128,8 @@ def write(self, vals): "one record.")) if (rec.review_ids and getattr(rec, self._state_field) in self._state_from and not vals.get(self._state_field) in - (self._state_to + [self._cancel_state])): + (self._state_to + [self._cancel_state]) and not + self._check_allow_write_under_validation(vals)): raise ValidationError(_("The operation is under validation.")) if vals.get(self._state_field) in self._state_from: self.mapped('review_ids').sudo().unlink() From 9ba9a2ea544978ba74a4d920ac848bebdf367716 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Fri, 23 Mar 2018 10:44:34 +0100 Subject: [PATCH 007/210] [9.0][IMP] base_tier_validation: * able to restart validation * sudo() not needed anymore --- base_tier_validation/__openerp__.py | 2 +- base_tier_validation/models/tier_validation.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/base_tier_validation/__openerp__.py b/base_tier_validation/__openerp__.py index ce34496eca..c9d97d9502 100644 --- a/base_tier_validation/__openerp__.py +++ b/base_tier_validation/__openerp__.py @@ -4,7 +4,7 @@ { "name": "Base Tier Validation", "summary": "Implement a validation process based on tiers.", - "version": "9.0.1.0.0", + "version": "9.0.1.0.1", "category": "Tools", "website": "https://github.com/OCA/server-tools", "author": "Eficent, Odoo Community Association (OCA)", diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index e6cd55990e..739b2d6645 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -15,7 +15,6 @@ class TierValidation(models.AbstractModel): _state_to = ['confirmed'] _cancel_state = 'cancel' - # TODO: reset validation? # TODO: step by step validation? review_ids = fields.One2many( @@ -69,6 +68,8 @@ def _compute_validated_rejected(self): @api.model def _calc_reviews_validated(self, reviews): """Override for different validation policy.""" + if not reviews: + return False return not any([s != 'approved' for s in reviews.mapped('status')]) @api.model @@ -122,7 +123,7 @@ def write(self, vals): raise ValidationError(_( "This action needs to be validated for at least " "one record. \nPlease request a validation.")) - if not rec.validated: + if rec.review_ids and not rec.validated: raise ValidationError(_( "A validation process is still open for at least " "one record.")) @@ -132,7 +133,7 @@ def write(self, vals): self._check_allow_write_under_validation(vals)): raise ValidationError(_("The operation is under validation.")) if vals.get(self._state_field) in self._state_from: - self.mapped('review_ids').sudo().unlink() + self.mapped('review_ids').unlink() return super(TierValidation, self).write(vals) def _validate_tier(self, tiers=False): @@ -179,3 +180,9 @@ def request_validation(self): }) # TODO: notify? post some msg in chatter? return created_trs + + @api.multi + def restart_validation(self): + for rec in self: + if getattr(rec, self._state_field) in self._state_from: + rec.mapped('review_ids').unlink() From eb761370484466953ec4011ecafde9d2e8f1e4b4 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Mon, 26 Mar 2018 13:23:15 +0200 Subject: [PATCH 008/210] [10.0][MIG] base_tier_validation --- base_tier_validation/README.rst | 2 +- base_tier_validation/{__openerp__.py => __manifest__.py} | 2 +- base_tier_validation/models/tier_definition.py | 2 +- base_tier_validation/models/tier_review.py | 2 +- base_tier_validation/models/tier_validation.py | 6 +++--- base_tier_validation/views/tier_definition_view.xml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename base_tier_validation/{__openerp__.py => __manifest__.py} (95%) diff --git a/base_tier_validation/README.rst b/base_tier_validation/README.rst index 8e27d1d467..76bf575ffa 100644 --- a/base_tier_validation/README.rst +++ b/base_tier_validation/README.rst @@ -27,7 +27,7 @@ To configure this module, you need to: .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/149/9.0 + :target: https://runbot.odoo-community.org/runbot/149/10.0 Known issues / Roadmap ====================== diff --git a/base_tier_validation/__openerp__.py b/base_tier_validation/__manifest__.py similarity index 95% rename from base_tier_validation/__openerp__.py rename to base_tier_validation/__manifest__.py index c9d97d9502..1f2df18a48 100644 --- a/base_tier_validation/__openerp__.py +++ b/base_tier_validation/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Base Tier Validation", "summary": "Implement a validation process based on tiers.", - "version": "9.0.1.0.1", + "version": "10.0.1.0.0", "category": "Tools", "website": "https://github.com/OCA/server-tools", "author": "Eficent, Odoo Community Association (OCA)", diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py index ffa81446ef..c1ef1f9f3a 100644 --- a/base_tier_validation/models/tier_definition.py +++ b/base_tier_validation/models/tier_definition.py @@ -2,7 +2,7 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from openerp import api, fields, models +from odoo import api, fields, models class TierDefinition(models.Model): diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py index e7afe7a728..e34e713c13 100644 --- a/base_tier_validation/models/tier_review.py +++ b/base_tier_validation/models/tier_review.py @@ -2,7 +2,7 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from openerp import api, fields, models +from odoo import api, fields, models class TierReview(models.Model): diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 739b2d6645..ff7a4ea3b5 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -2,9 +2,9 @@ # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from openerp import api, fields, models, _ -from openerp.exceptions import ValidationError, UserError -from openerp.tools.safe_eval import safe_eval +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError, UserError +from odoo.tools.safe_eval import safe_eval class TierValidation(models.AbstractModel): diff --git a/base_tier_validation/views/tier_definition_view.xml b/base_tier_validation/views/tier_definition_view.xml index 5511b38b5d..5aadc35514 100644 --- a/base_tier_validation/views/tier_definition_view.xml +++ b/base_tier_validation/views/tier_definition_view.xml @@ -37,7 +37,7 @@ - + From bcc420b6027693d861de9d5e05a77ab219ef1d2e Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Wed, 9 May 2018 17:08:13 +0200 Subject: [PATCH 009/210] [11.0][MIG] base_tier_validation --- base_tier_validation/README.rst | 2 +- base_tier_validation/__init__.py | 1 - base_tier_validation/__manifest__.py | 5 ++--- base_tier_validation/models/__init__.py | 1 - base_tier_validation/models/tier_definition.py | 1 - base_tier_validation/models/tier_review.py | 1 - base_tier_validation/models/tier_validation.py | 3 +-- 7 files changed, 4 insertions(+), 10 deletions(-) diff --git a/base_tier_validation/README.rst b/base_tier_validation/README.rst index 76bf575ffa..977eb446ce 100644 --- a/base_tier_validation/README.rst +++ b/base_tier_validation/README.rst @@ -27,7 +27,7 @@ To configure this module, you need to: .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/149/10.0 + :target: https://runbot.odoo-community.org/runbot/250/11.0 Known issues / Roadmap ====================== diff --git a/base_tier_validation/__init__.py b/base_tier_validation/__init__.py index b44d765940..31660d6a96 100644 --- a/base_tier_validation/__init__.py +++ b/base_tier_validation/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import models diff --git a/base_tier_validation/__manifest__.py b/base_tier_validation/__manifest__.py index 1f2df18a48..febb73f4c3 100644 --- a/base_tier_validation/__manifest__.py +++ b/base_tier_validation/__manifest__.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). { "name": "Base Tier Validation", "summary": "Implement a validation process based on tiers.", - "version": "10.0.1.0.0", + "version": "11.0.1.0.0", "category": "Tools", - "website": "https://github.com/OCA/server-tools", + "website": "https://github.com/OCA/server-ux", "author": "Eficent, Odoo Community Association (OCA)", "license": "AGPL-3", "application": False, diff --git a/base_tier_validation/models/__init__.py b/base_tier_validation/models/__init__.py index d7c418aa8f..2c43513f08 100644 --- a/base_tier_validation/models/__init__.py +++ b/base_tier_validation/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import tier_definition diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py index c1ef1f9f3a..1a027c0ce0 100644 --- a/base_tier_validation/models/tier_definition.py +++ b/base_tier_validation/models/tier_definition.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py index e34e713c13..c5f46dcd22 100644 --- a/base_tier_validation/models/tier_review.py +++ b/base_tier_validation/models/tier_review.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index ff7a4ea3b5..5b6ec5faef 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2017 Eficent Business and IT Consulting Services S.L. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). @@ -90,7 +89,7 @@ def _compute_need_validation(self): def evaluate_tier(self, tier): try: res = safe_eval(tier.python_code, globals_dict={'rec': self}) - except Exception, error: + except Exception as error: raise UserError(_( "Error evaluating tier validation conditions.\n %s") % error) return res From f86eaa24dcafc4cc85aa0a28e4c42fac504f816a Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Thu, 10 May 2018 11:28:45 +0200 Subject: [PATCH 010/210] [11.0][IMP] base_tier_validation: add tests --- base_tier_validation/tests/__init__.py | 4 + base_tier_validation/tests/common.py | 13 ++ .../tests/test_tier_validation.py | 150 ++++++++++++++++++ .../tests/tier_validation_tester.py | 21 +++ 4 files changed, 188 insertions(+) create mode 100644 base_tier_validation/tests/__init__.py create mode 100644 base_tier_validation/tests/common.py create mode 100644 base_tier_validation/tests/test_tier_validation.py create mode 100644 base_tier_validation/tests/tier_validation_tester.py diff --git a/base_tier_validation/tests/__init__.py b/base_tier_validation/tests/__init__.py new file mode 100644 index 0000000000..c5d19b1934 --- /dev/null +++ b/base_tier_validation/tests/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import common +from . import test_tier_validation diff --git a/base_tier_validation/tests/common.py b/base_tier_validation/tests/common.py new file mode 100644 index 0000000000..b14a726d7f --- /dev/null +++ b/base_tier_validation/tests/common.py @@ -0,0 +1,13 @@ +# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + + +def setup_test_model(env, model_clses): + for model_cls in model_clses: + model_cls._build_model(env.registry, env.cr) + + env.registry.setup_models(env.cr) + env.registry.init_models( + env.cr, [model_cls._name for model_cls in model_clses], + dict(env.context, update_custom_fields=True) + ) diff --git a/base_tier_validation/tests/test_tier_validation.py b/base_tier_validation/tests/test_tier_validation.py new file mode 100644 index 0000000000..a2d70fb34f --- /dev/null +++ b/base_tier_validation/tests/test_tier_validation.py @@ -0,0 +1,150 @@ +# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo.tests import common +from odoo.exceptions import ValidationError, UserError +from .common import setup_test_model +from .tier_validation_tester import TierValidationTester + + +@common.at_install(False) +@common.post_install(True) +class TierTierValidation(common.SavepointCase): + + @classmethod + def setUpClass(cls): + super(TierTierValidation, cls).setUpClass() + + setup_test_model(cls.env, [TierValidationTester]) + + cls.test_model = cls.env[TierValidationTester._name] + + cls.tester_model = cls.env['ir.model'].search([ + ('model', '=', 'tier.validation.tester')]) + + # Access record: + cls.env["ir.model.access"].create({ + 'name': "access.tester", + 'model_id': cls.tester_model.id, + 'perm_read': 1, + 'perm_write': 1, + 'perm_create': 1, + 'perm_unlink': 1, + }) + + # Create users: + group_ids = cls.env.ref('base.group_system').ids + cls.test_user_1 = cls.env['res.users'].create({ + 'name': 'John', + 'login': 'test1', + 'groups_id': [(6, 0, group_ids)], + }) + cls.test_user_2 = cls.env['res.users'].create({ + 'name': 'Mike', + 'login': 'test2', + }) + + # Create tier definition: + cls.tier_def_obj = cls.env['tier.definition'] + cls.tier_def_obj.create({ + 'model_id': cls.tester_model.id, + 'review_type': 'individual', + 'reviewer_id': cls.test_user_1.id, + 'python_code': 'rec.test_field > 1.0', + }) + + cls.test_record = cls.test_model.create({ + 'test_field': 2.5, + }) + + def test_01_auto_validation(self): + """When the user can validate all future reviews, it is not needed + to request a validation, the action can be done straight forward.""" + self.test_record.sudo(self.test_user_1.id).action_confirm() + self.assertEqual(self.test_record.state, 'confirmed') + + def test_02_no_auto_validation(self): + """User with no right to validate future reviews must request a + validation.""" + with self.assertRaises(ValidationError): + self.test_record.sudo(self.test_user_2.id).action_confirm() + + def test_03_request_validation_approved(self): + """User 2 request a validation and user 1 approves it.""" + self.assertFalse(self.test_record.review_ids) + reviews = self.test_record.sudo( + self.test_user_2.id).request_validation() + self.assertTrue(reviews) + record = self.test_record.sudo(self.test_user_1.id) + record.validate_tier() + self.assertTrue(record.validated) + + def test_04_request_validation_rejected(self): + """Request validation, rejection and reset.""" + self.assertFalse(self.test_record.review_ids) + reviews = self.test_record.sudo( + self.test_user_2.id).request_validation() + self.assertTrue(reviews) + record = self.test_record.sudo(self.test_user_1.id) + record.reject_tier() + self.assertTrue(record.review_ids) + self.assertTrue(record.rejected) + record.restart_validation() + self.assertFalse(record.review_ids) + + def test_05_under_validation(self): + """Write is forbidden in a record under validation.""" + self.assertFalse(self.test_record.review_ids) + reviews = self.test_record.sudo( + self.test_user_2.id).request_validation() + self.assertTrue(reviews) + record = self.test_record.sudo(self.test_user_1.id) + with self.assertRaises(ValidationError): + record.write({'test_field': 0.5}) + + def test_06_validation_process_open(self): + """Operation forbidden while a validation process is open.""" + self.assertFalse(self.test_record.review_ids) + reviews = self.test_record.sudo( + self.test_user_2.id).request_validation() + self.assertTrue(reviews) + record = self.test_record.sudo(self.test_user_1.id) + with self.assertRaises(ValidationError): + record.action_confirm() + + def test_07_search_reviewers(self): + """Test search methods.""" + reviews = self.test_record.sudo( + self.test_user_2.id).request_validation() + self.assertTrue(reviews) + record = self.test_record.sudo(self.test_user_1.id) + self.assertIn(self.test_user_1, record.reviewer_ids) + res = self.test_model.search( + [('reviewer_ids', 'in', self.test_user_1.id)]) + self.assertTrue(res) + + def test_08_search_validated(self): + """Test for the validated search method.""" + self.test_record.sudo(self.test_user_2.id).request_validation() + res = self.test_model.sudo(self.test_user_1.id).search( + [('validated', '=', False)]) + self.assertTrue(res) + + def test_09_wrong_tier_definition(self): + """Error should raise with incorrect python expresions on + tier definitions.""" + self.tier_def_obj.create({ + 'model_id': self.tester_model.id, + 'review_type': 'individual', + 'reviewer_id': self.test_user_1.id, + 'python_code': 'rec.not_existing_field > 1.0', + }) + with self.assertRaises(UserError): + self.test_record.sudo(self.test_user_1.id).action_confirm() + + def test_10_dummy_tier_definition(self): + """Test tier.definition methods.""" + res = self.tier_def_obj._get_tier_validation_model_names() + self.assertEqual(res, []) + res = self.tier_def_obj.onchange_model_id() + self.assertTrue(res) diff --git a/base_tier_validation/tests/tier_validation_tester.py b/base_tier_validation/tests/tier_validation_tester.py new file mode 100644 index 0000000000..dc51cafc6b --- /dev/null +++ b/base_tier_validation/tests/tier_validation_tester.py @@ -0,0 +1,21 @@ +# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class TierValidationTester(models.Model): + _name = 'tier.validation.tester' + _inherit = ['tier.validation'] + + state = fields.Selection( + selection=[('draft', 'Draft'), + ('confirmed', 'Confirmed'), + ('cancel', 'Cancel')], + default='draft', + ) + test_field = fields.Float() + + @api.multi + def action_confirm(self): + self.write({'state': 'confirmed'}) From 6b52b14c676fc7e0ccd82c9531c857b7d439f714 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Tue, 3 Jul 2018 17:13:18 +0200 Subject: [PATCH 011/210] add 'can_review' to tier.validation so that the buttons approve and reject can be hidden according to this computed field. --- base_tier_validation/models/tier_validation.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 5b6ec5faef..66473a125f 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -33,6 +33,12 @@ class TierValidation(models.AbstractModel): compute="_compute_reviewer_ids", search="_search_reviewer_ids", ) + can_review = fields.Boolean(compute="_compute_can_review") + + @api.multi + def _compute_can_review(self): + for rec in self: + rec.can_review = self.env.user in rec.reviewer_ids @api.multi @api.depends('review_ids') From 02b8238c7d493d75e8fff39cd95fe83720dfdb6a Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Tue, 15 Jan 2019 13:02:58 +0100 Subject: [PATCH 012/210] [11.0][IMP] base_tier_validation: enhance views and register who does and who asks for reviews in new fields 'done_by' and 'requested_by'. --- base_tier_validation/README.rst | 74 ++- base_tier_validation/__manifest__.py | 4 +- base_tier_validation/models/tier_review.py | 6 + .../models/tier_validation.py | 11 +- base_tier_validation/readme/CONFIGURE.rst | 5 + base_tier_validation/readme/CONTRIBUTORS.rst | 1 + base_tier_validation/readme/DESCRIPTION.rst | 9 + base_tier_validation/readme/ROADMAP.rst | 1 + .../static/description/index.html | 443 ++++++++++++++++++ .../views/tier_definition_view.xml | 60 ++- .../views/tier_review_view.xml | 2 + 11 files changed, 575 insertions(+), 41 deletions(-) create mode 100644 base_tier_validation/readme/CONFIGURE.rst create mode 100644 base_tier_validation/readme/CONTRIBUTORS.rst create mode 100644 base_tier_validation/readme/DESCRIPTION.rst create mode 100644 base_tier_validation/readme/ROADMAP.rst create mode 100644 base_tier_validation/static/description/index.html diff --git a/base_tier_validation/README.rst b/base_tier_validation/README.rst index 977eb446ce..6d5a4fff01 100644 --- a/base_tier_validation/README.rst +++ b/base_tier_validation/README.rst @@ -1,11 +1,30 @@ -.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png - :target: https://www.gnu.org/licenses/agpl - :alt: License: AGPL-3 - ==================== Base Tier Validation ==================== +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Mature-brightgreen.png + :target: https://odoo-community.org/page/development-status + :alt: Mature +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--ux-lightgray.png?logo=github + :target: https://github.com/OCA/server-ux/tree/11.0/base_tier_validation + :alt: OCA/server-ux +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-ux-11-0/server-ux-11-0-base_tier_validation + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/250/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + This module does not provide a functionality by itself but an abstract model to implement a validation process based on tiers on other models (e.g. purchase orders, sales orders...). @@ -16,6 +35,11 @@ development. See `purchase_tier_validation `_ as an example of implementation. +**Table of contents** + +.. contents:: + :local: + Configuration ============= @@ -25,10 +49,6 @@ To configure this module, you need to: #. Create as many tiers as you want for any model having tier validation functionality. -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/250/11.0 - Known issues / Roadmap ====================== @@ -37,37 +57,47 @@ Known issues / Roadmap Bug Tracker =========== -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smash it by providing detailed and welcomed feedback. +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. Credits ======= -Images ------- +Authors +~~~~~~~ -* Odoo Community Association: `Icon `_. +* Eficent Contributors ------------- +~~~~~~~~~~~~ * Lois Rilo -Do not contact contributors directly about support or help with technical issues. +Maintainers +~~~~~~~~~~~ -Maintainer ----------- +This module is maintained by the OCA. .. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association :target: https://odoo-community.org -This module is maintained by the OCA. - OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit https://odoo-community.org. +.. |maintainer-lreficent| image:: https://github.com/lreficent.png?size=40px + :target: https://github.com/lreficent + :alt: lreficent + +Current `maintainer `__: + +|maintainer-lreficent| + +This module is part of the `OCA/server-ux `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_tier_validation/__manifest__.py b/base_tier_validation/__manifest__.py index febb73f4c3..667ae85f61 100644 --- a/base_tier_validation/__manifest__.py +++ b/base_tier_validation/__manifest__.py @@ -3,7 +3,9 @@ { "name": "Base Tier Validation", "summary": "Implement a validation process based on tiers.", - "version": "11.0.1.0.0", + "version": "11.0.1.1.0", + "development_status": "Mature", + "maintainers": ['lreficent'], "category": "Tools", "website": "https://github.com/OCA/server-ux", "author": "Eficent, Odoo Community Association (OCA)", diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py index c5f46dcd22..5e1c9c2ae8 100644 --- a/base_tier_validation/models/tier_review.py +++ b/base_tier_validation/models/tier_review.py @@ -32,6 +32,12 @@ class TierReview(models.Model): compute="_compute_reviewer_ids", store=True, ) sequence = fields.Integer(string="Tier") + done_by = fields.Many2one( + comodel_name="res.users", + ) + requested_by = fields.Many2one( + comodel_name="res.users", + ) @api.multi @api.depends('reviewer_id', 'reviewer_group_id', 'reviewer_group_id.users') diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 66473a125f..10ff646755 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -148,7 +148,10 @@ def _validate_tier(self, tiers=False): lambda r: r.status in ('pending', 'rejected') and (r.reviewer_id == self.env.user or r.reviewer_group_id in self.env.user.groups_id)) - user_reviews.write({'status': 'approved'}) + user_reviews.write({ + 'status': 'approved', + 'done_by': self.env.user.id, + }) @api.multi def validate_tier(self): @@ -162,7 +165,10 @@ def reject_tier(self): lambda r: r.status in ('pending', 'approved') and (r.reviewer_id == self.env.user or r.reviewer_group_id in self.env.user.groups_id)) - user_reviews.write({'status': 'rejected'}) + user_reviews.write({ + 'status': 'rejected', + 'done_by': self.env.user.id, + }) @api.multi def request_validation(self): @@ -182,6 +188,7 @@ def request_validation(self): 'res_id': rec.id, 'definition_id': td.id, 'sequence': sequence, + 'requested_by': self.env.uid, }) # TODO: notify? post some msg in chatter? return created_trs diff --git a/base_tier_validation/readme/CONFIGURE.rst b/base_tier_validation/readme/CONFIGURE.rst new file mode 100644 index 0000000000..11fb42e01e --- /dev/null +++ b/base_tier_validation/readme/CONFIGURE.rst @@ -0,0 +1,5 @@ +To configure this module, you need to: + +#. Go to *Settings > Technical > Tier Validations > Tier Definition*. +#. Create as many tiers as you want for any model having tier validation + functionality. diff --git a/base_tier_validation/readme/CONTRIBUTORS.rst b/base_tier_validation/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..4b574636c0 --- /dev/null +++ b/base_tier_validation/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Lois Rilo diff --git a/base_tier_validation/readme/DESCRIPTION.rst b/base_tier_validation/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..d314eab0fe --- /dev/null +++ b/base_tier_validation/readme/DESCRIPTION.rst @@ -0,0 +1,9 @@ +This module does not provide a functionality by itself but an abstract model +to implement a validation process based on tiers on other models (e.g. +purchase orders, sales orders...). + +**Note:** To be able to use this module in a new model you will need some +development. + +See `purchase_tier_validation `_ as an example of implementation. diff --git a/base_tier_validation/readme/ROADMAP.rst b/base_tier_validation/readme/ROADMAP.rst new file mode 100644 index 0000000000..54bada4e8e --- /dev/null +++ b/base_tier_validation/readme/ROADMAP.rst @@ -0,0 +1 @@ +* In odoo v11 it would be interesting to try to take advantage of ``mail.activity.mixin``. diff --git a/base_tier_validation/static/description/index.html b/base_tier_validation/static/description/index.html new file mode 100644 index 0000000000..ff0ae9bf32 --- /dev/null +++ b/base_tier_validation/static/description/index.html @@ -0,0 +1,443 @@ + + + + + + +Base Tier Validation + + + +
+

Base Tier Validation

+ + +

Mature License: AGPL-3 OCA/server-ux Translate me on Weblate Try me on Runbot

+

This module does not provide a functionality by itself but an abstract model +to implement a validation process based on tiers on other models (e.g. +purchase orders, sales orders…).

+

Note: To be able to use this module in a new model you will need some +development.

+

See purchase_tier_validation as an example of implementation.

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to Settings > Technical > Tier Validations > Tier Definition.
  2. +
  3. Create as many tiers as you want for any model having tier validation +functionality.
  4. +
+
+
+

Known issues / Roadmap

+
    +
  • In odoo v11 it would be interesting to try to take advantage of mail.activity.mixin.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Eficent
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

lreficent

+

This module is part of the OCA/server-ux project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/base_tier_validation/views/tier_definition_view.xml b/base_tier_validation/views/tier_definition_view.xml index 5aadc35514..dafa6fc257 100644 --- a/base_tier_validation/views/tier_definition_view.xml +++ b/base_tier_validation/views/tier_definition_view.xml @@ -9,6 +9,9 @@ + + + @@ -21,34 +24,59 @@ tier.definition
- - - - - - + +
+ +
+ + + + + + + + + + + - - - - + + - - - - +
+ + tier.definition.search + tier.definition + + + + + + + + + + + + + + + Tier Definition ir.actions.act_window tier.definition form tree,form + {'search_default_all': 1} + +
From 1e509ead09507b74a6329011bcd984e33d94e291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Gil=20Sorribes?= Date: Fri, 15 Feb 2019 12:24:26 +0100 Subject: [PATCH 013/210] [11.0][FIX] base_tier_validation --- base_tier_validation/models/tier_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 10ff646755..0150bf429b 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -88,7 +88,7 @@ def _compute_need_validation(self): tiers = self.env[ 'tier.definition'].search([('model', '=', self._name)]) valid_tiers = any([self.evaluate_tier(tier) for tier in tiers]) - rec.need_validation = not self.review_ids and valid_tiers and \ + rec.need_validation = not rec.review_ids and valid_tiers and \ getattr(rec, self._state_field) in self._state_from @api.multi From 6bd9ae26ec8ca0840ae6306a217b78bd8d88269c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Gil=20Sorribes?= Date: Fri, 15 Feb 2019 13:45:50 +0100 Subject: [PATCH 014/210] Add name attribute to filter --- .../i18n/base_tier_validation.pot | 270 ++++++++++++++++++ .../views/tier_definition_view.xml | 2 +- 2 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 base_tier_validation/i18n/base_tier_validation.pot diff --git a/base_tier_validation/i18n/base_tier_validation.pot b/base_tier_validation/i18n/base_tier_validation.pot new file mode 100644 index 0000000000..219487b041 --- /dev/null +++ b/base_tier_validation/i18n/base_tier_validation.pot @@ -0,0 +1,270 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_tier_validation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_tier_validation +#: code:addons/base_tier_validation/models/tier_validation.py:132 +#, python-format +msgid "A validation process is still open for at least one record." +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_active +msgid "Active" +msgstr "" + +#. module: base_tier_validation +#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search +msgid "All" +msgstr "" + +#. module: base_tier_validation +#: selection:tier.definition,review_type:0 +msgid "Any user in a specific group." +msgstr "" + +#. module: base_tier_validation +#: selection:tier.review,status:0 +msgid "Approved" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_can_review +msgid "Can Review" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_company_id +msgid "Company" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_create_uid +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_create_uid +msgid "Created by" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_create_date +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_create_date +msgid "Created on" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_definition_id +msgid "Definition" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_display_name +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_display_name +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_display_name +msgid "Display Name" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_done_by +msgid "Done By" +msgstr "" + +#. module: base_tier_validation +#: code:addons/base_tier_validation/models/tier_validation.py:99 +#, python-format +msgid "Error evaluating tier validation conditions.\n" +" %s" +msgstr "" + +#. module: base_tier_validation +#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search +msgid "Group By" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_id +msgid "ID" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition___last_update +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review___last_update +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation___last_update +msgid "Last Modified on" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_write_uid +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_write_uid +msgid "Last Updated by" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_write_date +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_write_date +msgid "Last Updated on" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_model +#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search +msgid "Model" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_need_validation +msgid "Need Validation" +msgstr "" + +#. module: base_tier_validation +#: selection:tier.review,status:0 +msgid "Pending" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_model_id +msgid "Referenced Model" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_rejected +#: selection:tier.review,status:0 +msgid "Rejected" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_res_id +msgid "Related Document ID" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_model +msgid "Related Document Model" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_requested_by +msgid "Requested By" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_reviewer_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_reviewer_id +msgid "Reviewer" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_reviewer_group_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_reviewer_group_id +msgid "Reviewer group" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_reviewer_ids +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_reviewer_ids +msgid "Reviewers" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_sequence +msgid "Sequence" +msgstr "" + +#. module: base_tier_validation +#: selection:tier.definition,review_type:0 +msgid "Specific user" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_status +msgid "Status" +msgstr "" + +#. module: base_tier_validation +#: code:addons/base_tier_validation/models/tier_validation.py:139 +#, python-format +msgid "The operation is under validation." +msgstr "" + +#. module: base_tier_validation +#: code:addons/base_tier_validation/models/tier_validation.py:128 +#, python-format +msgid "This action needs to be validated for at least one record. \n" +"Please request a validation." +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_sequence +msgid "Tier" +msgstr "" + +#. module: base_tier_validation +#: model:ir.actions.act_window,name:base_tier_validation.tier_definition_action +#: model:ir.ui.menu,name:base_tier_validation.menu_tier_definition +#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_form +#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_tree +msgid "Tier Definition" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_python_code +msgid "Tier Definition Expression" +msgstr "" + +#. module: base_tier_validation +#: model:ir.ui.view,arch_db:base_tier_validation.tier_review_view_tree +msgid "Tier Review" +msgstr "" + +#. module: base_tier_validation +#: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation +msgid "Tier Validations" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_validated +msgid "Validated" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_review_type +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_review_type +msgid "Validated by" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_review_ids +msgid "Validations" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model.fields,help:base_tier_validation.field_tier_definition_python_code +msgid "Write Python code that defines when this tier confirmation will be needed. The result of executing the expresion must be a boolean." +msgstr "" + +#. module: base_tier_validation +#: model:ir.model,name:base_tier_validation.model_tier_definition +msgid "tier.definition" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model,name:base_tier_validation.model_tier_review +msgid "tier.review" +msgstr "" + +#. module: base_tier_validation +#: model:ir.model,name:base_tier_validation.model_tier_validation +msgid "tier.validation" +msgstr "" + diff --git a/base_tier_validation/views/tier_definition_view.xml b/base_tier_validation/views/tier_definition_view.xml index dafa6fc257..5fbc0c3e24 100644 --- a/base_tier_validation/views/tier_definition_view.xml +++ b/base_tier_validation/views/tier_definition_view.xml @@ -64,7 +64,7 @@ - + From abd06ad1b8a6b279550dc01d9f97d4c0b7356a4c Mon Sep 17 00:00:00 2001 From: Naglis Jonaitis Date: Mon, 18 Feb 2019 15:22:33 +0200 Subject: [PATCH 015/210] [MIG] base_tier_validation: Migration to 12.0 --- base_tier_validation/README.rst | 13 +++++++------ base_tier_validation/__manifest__.py | 2 +- base_tier_validation/models/tier_definition.py | 1 + base_tier_validation/models/tier_review.py | 1 + base_tier_validation/models/tier_validation.py | 1 + base_tier_validation/readme/CONTRIBUTORS.rst | 1 + base_tier_validation/readme/ROADMAP.rst | 2 +- base_tier_validation/static/description/index.html | 9 +++++---- 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/base_tier_validation/README.rst b/base_tier_validation/README.rst index 6d5a4fff01..13e593bca0 100644 --- a/base_tier_validation/README.rst +++ b/base_tier_validation/README.rst @@ -14,13 +14,13 @@ Base Tier Validation :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--ux-lightgray.png?logo=github - :target: https://github.com/OCA/server-ux/tree/11.0/base_tier_validation + :target: https://github.com/OCA/server-ux/tree/12.0/base_tier_validation :alt: OCA/server-ux .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/server-ux-11-0/server-ux-11-0-base_tier_validation + :target: https://translation.odoo-community.org/projects/server-ux-12-0/server-ux-12-0-base_tier_validation :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/250/11.0 + :target: https://runbot.odoo-community.org/runbot/250/12.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -52,7 +52,7 @@ To configure this module, you need to: Known issues / Roadmap ====================== -* In odoo v11 it would be interesting to try to take advantage of ``mail.activity.mixin``. +* Starting with Odoo v11 it would be interesting to try to take advantage of ``mail.activity.mixin``. Bug Tracker =========== @@ -60,7 +60,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -76,6 +76,7 @@ Contributors ~~~~~~~~~~~~ * Lois Rilo +* Naglis Jonaitis Maintainers ~~~~~~~~~~~ @@ -98,6 +99,6 @@ Current `maintainer `__: |maintainer-lreficent| -This module is part of the `OCA/server-ux `_ project on GitHub. +This module is part of the `OCA/server-ux `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_tier_validation/__manifest__.py b/base_tier_validation/__manifest__.py index 667ae85f61..a1b7c113f3 100644 --- a/base_tier_validation/__manifest__.py +++ b/base_tier_validation/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Base Tier Validation", "summary": "Implement a validation process based on tiers.", - "version": "11.0.1.1.0", + "version": "12.0.1.0.0", "development_status": "Mature", "maintainers": ['lreficent'], "category": "Tools", diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py index 1a027c0ce0..2dcc27f573 100644 --- a/base_tier_validation/models/tier_definition.py +++ b/base_tier_validation/models/tier_definition.py @@ -6,6 +6,7 @@ class TierDefinition(models.Model): _name = "tier.definition" + _description = "Tier Definition" _rec_name = "model_id" @api.model diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py index 5e1c9c2ae8..7e0b3a3a39 100644 --- a/base_tier_validation/models/tier_review.py +++ b/base_tier_validation/models/tier_review.py @@ -6,6 +6,7 @@ class TierReview(models.Model): _name = "tier.review" + _description = "Tier Review" status = fields.Selection( selection=[("pending", "Pending"), diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 0150bf429b..27c6aeb332 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -8,6 +8,7 @@ class TierValidation(models.AbstractModel): _name = "tier.validation" + _description = "Tier Validation (abstract)" _state_field = 'state' _state_from = ['draft'] diff --git a/base_tier_validation/readme/CONTRIBUTORS.rst b/base_tier_validation/readme/CONTRIBUTORS.rst index 4b574636c0..c228335362 100644 --- a/base_tier_validation/readme/CONTRIBUTORS.rst +++ b/base_tier_validation/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * Lois Rilo +* Naglis Jonaitis diff --git a/base_tier_validation/readme/ROADMAP.rst b/base_tier_validation/readme/ROADMAP.rst index 54bada4e8e..7cb7b880a8 100644 --- a/base_tier_validation/readme/ROADMAP.rst +++ b/base_tier_validation/readme/ROADMAP.rst @@ -1 +1 @@ -* In odoo v11 it would be interesting to try to take advantage of ``mail.activity.mixin``. +* Starting with Odoo v11 it would be interesting to try to take advantage of ``mail.activity.mixin``. diff --git a/base_tier_validation/static/description/index.html b/base_tier_validation/static/description/index.html index ff0ae9bf32..8279dea658 100644 --- a/base_tier_validation/static/description/index.html +++ b/base_tier_validation/static/description/index.html @@ -367,7 +367,7 @@

Base Tier Validation

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Mature License: AGPL-3 OCA/server-ux Translate me on Weblate Try me on Runbot

+

Mature License: AGPL-3 OCA/server-ux Translate me on Weblate Try me on Runbot

This module does not provide a functionality by itself but an abstract model to implement a validation process based on tiers on other models (e.g. purchase orders, sales orders…).

@@ -400,7 +400,7 @@

Configuration

Known issues / Roadmap

    -
  • In odoo v11 it would be interesting to try to take advantage of mail.activity.mixin.
  • +
  • Starting with Odoo v11 it would be interesting to try to take advantage of mail.activity.mixin.
@@ -408,7 +408,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -423,6 +423,7 @@

Authors

Contributors

@@ -434,7 +435,7 @@

Maintainers

promote its widespread use.

Current maintainer:

lreficent

-

This module is part of the OCA/server-ux project on GitHub.

+

This module is part of the OCA/server-ux project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From 212366524a8587cac0094ec82067eec5b3f85dd1 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 27 May 2019 10:52:25 +0000 Subject: [PATCH 016/210] [ADD] icon.png --- .../i18n/base_tier_validation.pot | 132 ++++++++---------- .../static/description/icon.png | Bin 0 -> 9455 bytes 2 files changed, 62 insertions(+), 70 deletions(-) create mode 100644 base_tier_validation/static/description/icon.png diff --git a/base_tier_validation/i18n/base_tier_validation.pot b/base_tier_validation/i18n/base_tier_validation.pot index 219487b041..1be5e7140d 100644 --- a/base_tier_validation/i18n/base_tier_validation.pot +++ b/base_tier_validation/i18n/base_tier_validation.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" +"Project-Id-Version: Odoo Server 12.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: <>\n" "Language-Team: \n" @@ -14,18 +14,18 @@ msgstr "" "Plural-Forms: \n" #. module: base_tier_validation -#: code:addons/base_tier_validation/models/tier_validation.py:132 +#: code:addons/base_tier_validation/models/tier_validation.py:133 #, python-format msgid "A validation process is still open for at least one record." msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_active +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__active msgid "Active" msgstr "" #. module: base_tier_validation -#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search +#: model_terms:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search msgid "All" msgstr "" @@ -40,90 +40,90 @@ msgid "Approved" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_can_review +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__can_review msgid "Can Review" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_company_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__company_id msgid "Company" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_create_uid -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_create_uid +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__create_uid +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__create_uid msgid "Created by" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_create_date -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_create_date +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__create_date +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__create_date msgid "Created on" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_definition_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__definition_id msgid "Definition" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_display_name -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_display_name -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_display_name +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__display_name +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__display_name +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__display_name msgid "Display Name" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_done_by +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__done_by msgid "Done By" msgstr "" #. module: base_tier_validation -#: code:addons/base_tier_validation/models/tier_validation.py:99 +#: code:addons/base_tier_validation/models/tier_validation.py:100 #, python-format msgid "Error evaluating tier validation conditions.\n" " %s" msgstr "" #. module: base_tier_validation -#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search +#: model_terms:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search msgid "Group By" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_id -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_id -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__id msgid "ID" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition___last_update -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review___last_update -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation___last_update +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition____last_update +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review____last_update +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation____last_update msgid "Last Modified on" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_write_uid -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_write_uid +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__write_uid +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__write_uid msgid "Last Updated by" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_write_date -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_write_date +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__write_date +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__write_date msgid "Last Updated on" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_model -#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__model +#: model_terms:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_search msgid "Model" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_need_validation +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__need_validation msgid "Need Validation" msgstr "" @@ -133,51 +133,51 @@ msgid "Pending" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_model_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__model_id msgid "Referenced Model" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_rejected +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__rejected #: selection:tier.review,status:0 msgid "Rejected" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_res_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__res_id msgid "Related Document ID" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_model +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__model msgid "Related Document Model" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_requested_by +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__requested_by msgid "Requested By" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_reviewer_id -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_reviewer_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__reviewer_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__reviewer_id msgid "Reviewer" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_reviewer_group_id -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_reviewer_group_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__reviewer_group_id +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__reviewer_group_id msgid "Reviewer group" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_reviewer_ids -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_reviewer_ids +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__reviewer_ids +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__reviewer_ids msgid "Reviewers" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_sequence +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__sequence msgid "Sequence" msgstr "" @@ -187,84 +187,76 @@ msgid "Specific user" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_status +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__status msgid "Status" msgstr "" #. module: base_tier_validation -#: code:addons/base_tier_validation/models/tier_validation.py:139 +#: code:addons/base_tier_validation/models/tier_validation.py:140 #, python-format msgid "The operation is under validation." msgstr "" #. module: base_tier_validation -#: code:addons/base_tier_validation/models/tier_validation.py:128 +#: code:addons/base_tier_validation/models/tier_validation.py:129 #, python-format msgid "This action needs to be validated for at least one record. \n" "Please request a validation." msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_sequence +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__sequence msgid "Tier" msgstr "" #. module: base_tier_validation #: model:ir.actions.act_window,name:base_tier_validation.tier_definition_action +#: model:ir.model,name:base_tier_validation.model_tier_definition #: model:ir.ui.menu,name:base_tier_validation.menu_tier_definition -#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_form -#: model:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_tree +#: model_terms:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_form +#: model_terms:ir.ui.view,arch_db:base_tier_validation.tier_definition_view_tree msgid "Tier Definition" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_python_code +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__python_code msgid "Tier Definition Expression" msgstr "" #. module: base_tier_validation -#: model:ir.ui.view,arch_db:base_tier_validation.tier_review_view_tree +#: model:ir.model,name:base_tier_validation.model_tier_review +#: model_terms:ir.ui.view,arch_db:base_tier_validation.tier_review_view_tree msgid "Tier Review" msgstr "" +#. module: base_tier_validation +#: model:ir.model,name:base_tier_validation.model_tier_validation +msgid "Tier Validation (abstract)" +msgstr "" + #. module: base_tier_validation #: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation msgid "Tier Validations" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_validated +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__validated msgid "Validated" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition_review_type -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review_review_type +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_definition__review_type +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_review__review_type msgid "Validated by" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation_review_ids +#: model:ir.model.fields,field_description:base_tier_validation.field_tier_validation__review_ids msgid "Validations" msgstr "" #. module: base_tier_validation -#: model:ir.model.fields,help:base_tier_validation.field_tier_definition_python_code +#: model:ir.model.fields,help:base_tier_validation.field_tier_definition__python_code msgid "Write Python code that defines when this tier confirmation will be needed. The result of executing the expresion must be a boolean." msgstr "" -#. module: base_tier_validation -#: model:ir.model,name:base_tier_validation.model_tier_definition -msgid "tier.definition" -msgstr "" - -#. module: base_tier_validation -#: model:ir.model,name:base_tier_validation.model_tier_review -msgid "tier.review" -msgstr "" - -#. module: base_tier_validation -#: model:ir.model,name:base_tier_validation.model_tier_validation -msgid "tier.validation" -msgstr "" - diff --git a/base_tier_validation/static/description/icon.png b/base_tier_validation/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 From 4c32246f9724392c66628c31c222823ccb60224a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Gil=20Sorribes?= Date: Mon, 25 Feb 2019 11:34:23 +0100 Subject: [PATCH 017/210] [11.0][IMP] base_tier_validation fixup and extend tests [ADD] systray icon for pending reviews [FIX] Remove python safe_eval [ADD] base_tier_validation_formula and migration scripts [ADD] widget domain and python expression to define reviewer in tier definition [ADD] auto updating of systray icon counter [ADD] validation date field [ADD] review widget dropdown menu --- base_tier_validation/__manifest__.py | 10 +- .../migrations/11.0.1.2.0/post-migrate.py | 16 +++ base_tier_validation/models/__init__.py | 1 + base_tier_validation/models/res_users.py | 38 +++++ .../models/tier_definition.py | 31 ++-- base_tier_validation/models/tier_review.py | 2 + .../models/tier_validation.py | 34 +++-- base_tier_validation/readme/CONTRIBUTORS.rst | 1 + .../static/src/js/review_widget.js | 58 ++++++++ base_tier_validation/static/src/js/systray.js | 135 ++++++++++++++++++ .../static/src/less/review.less | 4 + .../static/src/less/systray.less | 113 +++++++++++++++ .../static/src/xml/systray.xml | 41 ++++++ .../static/src/xml/tier_review_template.xml | 63 ++++++++ base_tier_validation/tests/common.py | 6 + .../tests/test_tier_validation.py | 84 ++++++++--- .../tests/tier_validation_tester.py | 21 +++ base_tier_validation/views/assets_backend.xml | 13 ++ .../views/tier_definition_view.xml | 31 +++- .../views/tier_review_view.xml | 4 +- 20 files changed, 656 insertions(+), 50 deletions(-) create mode 100644 base_tier_validation/migrations/11.0.1.2.0/post-migrate.py create mode 100644 base_tier_validation/models/res_users.py create mode 100644 base_tier_validation/static/src/js/review_widget.js create mode 100644 base_tier_validation/static/src/js/systray.js create mode 100644 base_tier_validation/static/src/less/review.less create mode 100644 base_tier_validation/static/src/less/systray.less create mode 100644 base_tier_validation/static/src/xml/systray.xml create mode 100644 base_tier_validation/static/src/xml/tier_review_template.xml create mode 100644 base_tier_validation/views/assets_backend.xml diff --git a/base_tier_validation/__manifest__.py b/base_tier_validation/__manifest__.py index a1b7c113f3..1f40cc9827 100644 --- a/base_tier_validation/__manifest__.py +++ b/base_tier_validation/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Base Tier Validation", "summary": "Implement a validation process based on tiers.", - "version": "12.0.1.0.0", + "version": "12.0.2.0.0", "development_status": "Mature", "maintainers": ['lreficent'], "category": "Tools", @@ -13,11 +13,17 @@ "application": False, "installable": True, "depends": [ - "base", + "web", + "bus", ], "data": [ "security/ir.model.access.csv", "views/tier_definition_view.xml", "views/tier_review_view.xml", + "views/assets_backend.xml", + ], + 'qweb': [ + 'static/src/xml/systray.xml', + 'static/src/xml/tier_review_template.xml', ], } diff --git a/base_tier_validation/migrations/11.0.1.2.0/post-migrate.py b/base_tier_validation/migrations/11.0.1.2.0/post-migrate.py new file mode 100644 index 0000000000..32d522211f --- /dev/null +++ b/base_tier_validation/migrations/11.0.1.2.0/post-migrate.py @@ -0,0 +1,16 @@ +# Copyright 2019 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openupgradelib.openupgrade import migrate + + +@migrate() +def migrate(env, version): + module_ids = env['ir.module.module'].search([ + ('name', '=', 'base_tier_validation_formula'), + ('state', '=', 'uninstalled') + ]) + if module_ids: + module_ids.sudo().button_install() + cr = env.cr + cr.execute("UPDATE tier_definition SET definition_type = 'formula'") diff --git a/base_tier_validation/models/__init__.py b/base_tier_validation/models/__init__.py index 2c43513f08..4bfc7acd0a 100644 --- a/base_tier_validation/models/__init__.py +++ b/base_tier_validation/models/__init__.py @@ -3,3 +3,4 @@ from . import tier_definition from . import tier_review from . import tier_validation +from . import res_users diff --git a/base_tier_validation/models/res_users.py b/base_tier_validation/models/res_users.py new file mode 100644 index 0000000000..930845de73 --- /dev/null +++ b/base_tier_validation/models/res_users.py @@ -0,0 +1,38 @@ +# Copyright 2019 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, modules + + +class Users(models.Model): + _inherit = 'res.users' + + review_ids = fields.Many2many( + string="Reviews", comodel_name="tier.review" + ) + + @api.model + def review_user_count(self): + user_reviews = {} + to_review_docs = {} + for review in self.env.user.review_ids.filtered( + lambda r: r.status == 'pending'): + record = review.env[review.model].browse(review.res_id) + if not user_reviews.get(review['model']): + user_reviews[review.model] = { + 'name': record._description, + 'model': review.model, + 'icon': modules.module.get_module_icon( + self.env[review.model]._original_module), + 'pending_count': 0 + } + docs = to_review_docs.get(review.model) + if (docs and record not in docs) or not docs: + user_reviews[review.model]['pending_count'] += 1 + to_review_docs.setdefault(review.model, []).append(record) + return list(user_reviews.values()) + + @api.model + def get_reviews(self, data): + return self.env['tier.review'].search_read( + [('id', 'in', data.get('res_ids'))]) diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py index 2dcc27f573..d49cacb8c5 100644 --- a/base_tier_validation/models/tier_definition.py +++ b/base_tier_validation/models/tier_definition.py @@ -7,13 +7,18 @@ class TierDefinition(models.Model): _name = "tier.definition" _description = "Tier Definition" - _rec_name = "model_id" + + @api.model + def _get_default_name(self): + return "New Tier Validation" @api.model def _get_tier_validation_model_names(self): res = [] return res + name = fields.Char( + 'Description', required=True, default=_get_default_name) model_id = fields.Many2one( comodel_name="ir.model", string="Referenced Model", @@ -23,8 +28,10 @@ def _get_tier_validation_model_names(self): ) review_type = fields.Selection( string="Validated by", default="individual", - selection=[("individual", "Specific user"), - ("group", "Any user in a specific group.")] + selection=[ + ("individual", "Specific user"), + ("group", "Any user in a specific group."), + ] ) reviewer_id = fields.Many2one( comodel_name="res.users", string="Reviewer", @@ -32,13 +39,14 @@ def _get_tier_validation_model_names(self): reviewer_group_id = fields.Many2one( comodel_name="res.groups", string="Reviewer group", ) - python_code = fields.Text( - string='Tier Definition Expression', - help="Write Python code that defines when this tier confirmation " - "will be needed. The result of executing the expresion must be " - "a boolean.", - default="""# Available locals:\n# - rec: current record""", + definition_type = fields.Selection( + string="Definition", + selection=[ + ('domain', 'Domain'), + ], + default='domain', ) + definition_domain = fields.Char() active = fields.Boolean(default=True) sequence = fields.Integer(default=30) company_id = fields.Many2one( @@ -52,3 +60,8 @@ def onchange_model_id(self): return {'domain': { 'model_id': [ ('model', 'in', self._get_tier_validation_model_names())]}} + + @api.onchange('review_type') + def onchange_review_type(self): + self.reviewer_id = None + self.reviewer_group_id = None diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py index 7e0b3a3a39..f86749b8de 100644 --- a/base_tier_validation/models/tier_review.py +++ b/base_tier_validation/models/tier_review.py @@ -8,6 +8,7 @@ class TierReview(models.Model): _name = "tier.review" _description = "Tier Review" + name = fields.Char(related="definition_id.name", readonly=True) status = fields.Selection( selection=[("pending", "Pending"), ("rejected", "Rejected"), @@ -39,6 +40,7 @@ class TierReview(models.Model): requested_by = fields.Many2one( comodel_name="res.users", ) + reviewed_date = fields.Datetime(string='Validation Date') @api.multi @api.depends('reviewer_id', 'reviewer_group_id', 'reviewer_group_id.users') diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 27c6aeb332..e2c84af131 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -2,8 +2,8 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import api, fields, models, _ -from odoo.exceptions import ValidationError, UserError -from odoo.tools.safe_eval import safe_eval +from odoo.exceptions import ValidationError +from ast import literal_eval class TierValidation(models.AbstractModel): @@ -23,6 +23,10 @@ class TierValidation(models.AbstractModel): domain=lambda self: [('model', '=', self._name)], auto_join=True, ) + review_ids_dropdown = fields.One2many( + related='review_ids', + help="Field needed to display the dropdown menu correctly" + ) validated = fields.Boolean( compute="_compute_validated_rejected", search="_search_validated", @@ -94,12 +98,10 @@ def _compute_need_validation(self): @api.multi def evaluate_tier(self, tier): - try: - res = safe_eval(tier.python_code, globals_dict={'rec': self}) - except Exception as error: - raise UserError(_( - "Error evaluating tier validation conditions.\n %s") % error) - return res + domain = [] + if tier.definition_domain: + domain = literal_eval(tier.definition_domain) + return self.search([('id', '=', self.id)] + domain) @api.model def _get_under_validation_exceptions(self): @@ -147,12 +149,13 @@ def _validate_tier(self, tiers=False): tier_reviews = tiers or self.review_ids user_reviews = tier_reviews.filtered( lambda r: r.status in ('pending', 'rejected') and - (r.reviewer_id == self.env.user or - r.reviewer_group_id in self.env.user.groups_id)) + (self.env.user in r.reviewer_ids)) user_reviews.write({ 'status': 'approved', 'done_by': self.env.user.id, + 'reviewed_date': fields.Datetime.now(), }) + # TODO: add message_post @api.multi def validate_tier(self): @@ -169,7 +172,9 @@ def reject_tier(self): user_reviews.write({ 'status': 'rejected', 'done_by': self.env.user.id, + 'reviewed_date': fields.Datetime.now(), }) + # TODO: Add Message_post @api.multi def request_validation(self): @@ -191,7 +196,7 @@ def request_validation(self): 'sequence': sequence, 'requested_by': self.env.uid, }) - # TODO: notify? post some msg in chatter? + self._update_counter() return created_trs @api.multi @@ -199,3 +204,10 @@ def restart_validation(self): for rec in self: if getattr(rec, self._state_field) in self._state_from: rec.mapped('review_ids').unlink() + self._update_counter() + + def _update_counter(self): + notifications = [] + channel = 'base.tier.validation' + notifications.append([channel, {}]) + self.env['bus.bus'].sendmany(notifications) diff --git a/base_tier_validation/readme/CONTRIBUTORS.rst b/base_tier_validation/readme/CONTRIBUTORS.rst index c228335362..98446a066b 100644 --- a/base_tier_validation/readme/CONTRIBUTORS.rst +++ b/base_tier_validation/readme/CONTRIBUTORS.rst @@ -1,2 +1,3 @@ * Lois Rilo * Naglis Jonaitis +* Adrià Gil Sorribes diff --git a/base_tier_validation/static/src/js/review_widget.js b/base_tier_validation/static/src/js/review_widget.js new file mode 100644 index 0000000000..cdc454e4ec --- /dev/null +++ b/base_tier_validation/static/src/js/review_widget.js @@ -0,0 +1,58 @@ +odoo.define('base_tier_validation.ReviewField', function (require) { + "use strict"; + + var AbstractField = require('web.AbstractField'); + var core = require('web.core'); + var session = require('web.session'); + var field_registry = require('web.field_registry'); + var Widget = require('web.Widget'); + + var _t = core._t; + var QWeb = core.qweb; + + var ReviewField = AbstractField.extend({ + template: 'tier.review.ReviewPopUp', + events: { + 'click .o_info_btn': '_onButtonClicked', + }, + start: function () { + var self = this; + console.log(self) + + }, + /** + * Make RPC and get current user's activity details + * @private + */ + _getReviewData: function(res_ids){ + var self = this; + + return self._rpc({ + model: 'res.users', + method: 'get_reviews', + args: [res_ids], + }).then(function (data) { + self.reviews = data; + }); + }, + _renderDropdown: function () { + var self = this; + return this._getReviewData(self.value).then(function (){ + self.$('.o_review').html(QWeb.render("tier.review.ReviewDropDown", { + reviews : self.reviews + })); + }); + }, + _onButtonClicked: function (event) { + event.preventDefault(); + if (!this.$el.hasClass('open')) { + this._renderDropdown(); + } + }, + }); + + field_registry.add('review_popup', ReviewField); + + return ReviewField; + + }); \ No newline at end of file diff --git a/base_tier_validation/static/src/js/systray.js b/base_tier_validation/static/src/js/systray.js new file mode 100644 index 0000000000..9b658e0660 --- /dev/null +++ b/base_tier_validation/static/src/js/systray.js @@ -0,0 +1,135 @@ +odoo.define('tier_validation.systray', function (require) { + "use strict"; + + var config = require('web.config'); + var core = require('web.core'); + var session = require('web.session'); + var SystrayMenu = require('web.SystrayMenu'); + var Widget = require('web.Widget'); + var bus = require('bus.bus').bus; + + var chat_manager = require('mail.chat_manager'); + + var QWeb = core.qweb; + + var ReviewMenu = Widget.extend({ + template:'tier.validation.ReviewMenu', + events: { + "click": "_onReviewMenuClick", + "click .o_mail_channel_preview": "_onReviewFilterClick", + }, + start: function () { + this.$reviews_preview = this.$('.o_mail_navbar_dropdown_channels'); + this._updateReviewPreview(); + var channel = 'base.tier.validation'; + bus.add_channel(channel); + bus.on('notification', this, this._updateReviewPreview); + return this._super(); + }, + + // Private + + /** + * Make RPC and get current user's activity details + * @private + */ + _getReviewData: function(){ + var self = this; + + return self._rpc({ + model: 'res.users', + method: 'review_user_count', + kwargs: { + context: session.user_context, + }, + }).then(function (data) { + self.reviews = data; + self.reviewCounter = _.reduce(data, function(total_count, p_data){ return total_count + p_data.pending_count; }, 0); + self.$('.o_notification_counter').text(self.reviewCounter); + self.$el.toggleClass('o_no_notification', !self.reviewCounter); + }); + }, + /** + * Check wether activity systray dropdown is open or not + * @private + * @returns {boolean} + */ + _isOpen: function () { + return this.$el.hasClass('open'); + }, + /** + * Update(render) activity system tray view on activity updation. + * @private + */ + _updateReviewPreview: function () { + var self = this; + self._getReviewData().then(function (){ + self.$reviews_preview.html(QWeb.render('tier.validation.ReviewMenuPreview', { + reviews : self.reviews + })); + }); + }, + /** + * update counter based on activity status(created or Done) + * @private + * @param {Object} [data] key, value to decide activity created or deleted + * @param {String} [data.type] notification type + * @param {Boolean} [data.activity_deleted] when activity deleted + * @param {Boolean} [data.activity_created] when activity created + */ + _updateCounter: function (data) { + if (data) { + if (data.review_created) { + this.reviewCounter ++; + } + if (data.review_deleted && this.reviewCounter > 0) { + this.reviewCounter --; + } + this.$('.o_notification_counter').text(this.reviewCounter); + this.$el.toggleClass('o_no_notification', !this.reviewCounter); + } + }, + + + // Handlers + + /** + * Redirect to particular model view + * @private + * @param {MouseEvent} event + */ + _onReviewFilterClick: function (event) { + // fetch the data from the button otherwise fetch the ones from the parent (.o_tier_channel_preview). + var data = _.extend({}, $(event.currentTarget).data(), $(event.target).data()); + var context = {}; + this.do_action({ + type: 'ir.actions.act_window', + name: data.model_name, + res_model: data.res_model, + views: [[false, 'list'], [false, 'form']], + search_view_id: [false], + domain: [['review_ids.reviewer_ids', '=', session.uid], + ['review_ids.status', '=', 'pending']], + context:context, + }); + }, + /** + * When menu clicked update activity preview if counter updated + * @private + * @param {MouseEvent} event + */ + _onReviewMenuClick: function () { + if (!this._isOpen()) { + this._updateReviewPreview(); + } + }, + + }); + + SystrayMenu.Items.push(ReviewMenu); + + // to test activity menu in qunit test cases we need it + return { + ReviewMenu: ReviewMenu, + }; +}); \ No newline at end of file diff --git a/base_tier_validation/static/src/less/review.less b/base_tier_validation/static/src/less/review.less new file mode 100644 index 0000000000..e47e821955 --- /dev/null +++ b/base_tier_validation/static/src/less/review.less @@ -0,0 +1,4 @@ +ul.o_review { + min-width: 600px; + max-width: 800px +} \ No newline at end of file diff --git a/base_tier_validation/static/src/less/systray.less b/base_tier_validation/static/src/less/systray.less new file mode 100644 index 0000000000..24a43f564d --- /dev/null +++ b/base_tier_validation/static/src/less/systray.less @@ -0,0 +1,113 @@ +// Navbar icon and dropdown +.o_tier_navbar_item { + > a { + opacity: 1; + > i { + font-size: larger; + } + } + &.o_no_notification > a { + opacity: 0.5; + > i { + .o-transform(translateY(0px)); + } + .o_notification_counter { + display: none; + } + } + &.open .o_tier_navbar_dropdown { + .o-flex-display(); + .o-flex-flow(column, nowrap); + } + .o_notification_counter { + .o-position-absolute(@top: 20%, @right: 1px); + background: @odoo-brand-optional; + color: white; + padding: 0em 0.3em; + font-size: 0.7em; + } + .o_tier_navbar_dropdown { + width: 350px; + padding: 0; + + .o_spinner { + .o-flex-display(); + .o-align-items(center); + .o-justify-content(center); + color: @odoo-main-text-color; + height: 50px; + } + + .o_tier_navbar_dropdown_channels { + .o-flex(0, 1, auto); + max-height: 400px; + min-height: 50px; + overflow-y: auto; + + @media (min-width: @screen-sm-min) { + .o_tier_channel_preview { + height: 50px; + padding: 5px; + .o_tier_channel_image { + width: 40px; + } + .o_channel_info { + margin-left: 10px; + .o_channel_title { + .o_last_message_date { + padding-top: 2px; + font-size: x-small; + margin-left: 10px; + } + } + } + } + } + } + .o_no_review { + cursor: initial; + .o-align-items(center); + color: grey; + opacity: 0.5; + padding: 3px; + } + } +} + +.o_no_chat_window .o_tier_navbar_dropdown .o_new_message { + display: none; // hide 'new message' button if chat windows are disabled +} + +// Mobile rules +// Goal: mock the design of Discuss in mobile +@media (max-width: @screen-xs-max) { + .o_tier_navbar_item { + .o_notification_counter { + top: 10%; + } + .o_tier_navbar_dropdown { + position: relative; + .o_tier_navbar_dropdown_top { + padding: 5px; + } + .o_tier_navbar_mobile_header { + padding: 5px; + height: 44px; + border-bottom: 1px solid #ebebeb; + box-shadow: 0 0 2px @gray-lighter-darker; + } + .o_tier_navbar_dropdown_channels { + max-height: none; + padding-bottom: 52px; // leave space for tabs + } + .o_tier_mobile_tabs { + position: fixed; + bottom: 0px; + left: 0px; + right: 0px; + background-color: white; + color: @odoo-main-text-color; + } + } + } +} diff --git a/base_tier_validation/static/src/xml/systray.xml b/base_tier_validation/static/src/xml/systray.xml new file mode 100644 index 0000000000..55962d1af3 --- /dev/null +++ b/base_tier_validation/static/src/xml/systray.xml @@ -0,0 +1,41 @@ + + + + + +
  • + No reviews to do. +
  • +
    + +
    +
    + +
    +
    +
    + + + +
    +
    + + 0 Pending +
    +
    +
    +
    +
    + + +
  • + + +
  • +
    + +
    diff --git a/base_tier_validation/static/src/xml/tier_review_template.xml b/base_tier_validation/static/src/xml/tier_review_template.xml new file mode 100644 index 0000000000..0154a8e1f7 --- /dev/null +++ b/base_tier_validation/static/src/xml/tier_review_template.xml @@ -0,0 +1,63 @@ + + + + +