diff --git a/base_tier_validation_forward/models/tier_definition.py b/base_tier_validation_forward/models/tier_definition.py index 941f7817ec..a86b355b81 100644 --- a/base_tier_validation_forward/models/tier_definition.py +++ b/base_tier_validation_forward/models/tier_definition.py @@ -11,3 +11,8 @@ class TierDefinition(models.Model): default=False, help="Allow option to 'Forward' to different person.", ) + backward = fields.Boolean( + string="Backward", + help="If the forwarded step is approved, " + "auto forward back again to finish the step.", + ) diff --git a/base_tier_validation_forward/models/tier_review.py b/base_tier_validation_forward/models/tier_review.py index af2ece3a9a..61b36c5be3 100644 --- a/base_tier_validation_forward/models/tier_review.py +++ b/base_tier_validation_forward/models/tier_review.py @@ -31,6 +31,11 @@ class TierReview(models.Model): approve_sequence = fields.Boolean( compute="_compute_definition_data", store=True, readonly=False, ) + origin_id = fields.Many2one( + comodel_name="tier.review", + copy=False, + help="Reference to origin tier review that createāļ this tier.", + ) @api.depends( "definition_id.name", diff --git a/base_tier_validation_forward/models/tier_validation.py b/base_tier_validation_forward/models/tier_validation.py index a37b902fa3..9f92327ad3 100644 --- a/base_tier_validation_forward/models/tier_validation.py +++ b/base_tier_validation_forward/models/tier_validation.py @@ -7,6 +7,7 @@ class TierValidation(models.AbstractModel): _inherit = "tier.validation" can_forward = fields.Boolean(compute="_compute_can_forward") + can_backward = fields.Boolean(compute="_compute_can_backward") def _compute_can_forward(self): for rec in self: @@ -18,6 +19,16 @@ def _compute_can_forward(self): definitions = reviews.mapped("definition_id") rec.can_forward = True in definitions.mapped("has_forward") + def _compute_can_backward(self): + for rec in self: + if not rec.can_review: + rec.can_backward = False + continue + sequences = self._get_sequences_to_approve(self.env.user) + reviews = rec.review_ids.filtered(lambda l: l.sequence in sequences) + definitions = reviews.mapped("definition_id") + rec.can_backward = True in definitions.mapped("backward") + @api.model def _calc_reviews_validated(self, reviews): """Override for different validation policy.""" @@ -73,7 +84,7 @@ def _notify_forwarded_reviews(self): post = "message_post" if hasattr(self, post): # Notify state change - getattr(self, post)( + getattr(self.sudo(), post)( subtype=self._get_forwarded_notification_subtype(), body=self._notify_forwarded_reviews_body(), ) @@ -88,3 +99,33 @@ def _notify_forwarded_reviews_body(self): "A review was forwarded from {} {}".format(self.env.user.name, comment) ) return _("A review was forwarded by %s.") % (self.env.user.name) + + def _validate_tier(self, tiers=False): + self.ensure_one() + backwards = self._create_backward(tiers) + super()._validate_tier(tiers=tiers) + backwards._compute_can_review() + + def _create_backward(self, tiers): + """ Find the forward tier that require to backward """ + tier_reviews = tiers or self.review_ids + to_backward_reviews = tier_reviews.filtered( + lambda r: r.status == "pending" + and (self.env.user in r.reviewer_ids) + and r.origin_id.definition_id.has_forward # Forward + and r.origin_id.definition_id.backward # To Backward + ) + created_backward_reviews = self.env["tier.review"] + for review in to_backward_reviews: + new_backward_tier = review.origin_id.copy( + { + "sequence": round(review.sequence + 0.1, 2), + "done_by": False, + "reviewed_date": False, + "status": "pending", + "comment": False, + "origin_id": False, + } + ) + created_backward_reviews += new_backward_tier + return created_backward_reviews diff --git a/base_tier_validation_forward/tests/test_tier_validation.py b/base_tier_validation_forward/tests/test_tier_validation.py index a19e758070..449ea222ff 100644 --- a/base_tier_validation_forward/tests/test_tier_validation.py +++ b/base_tier_validation_forward/tests/test_tier_validation.py @@ -118,3 +118,71 @@ def test_01_forward_tier(self): wiz = wizard.save() wiz.add_comment() self.assertTrue(record.validated) + + def test_02_forward_tier_backward(self): + # Create new test record + test_record = self.test_model.create({"test_field": 2.5}) + # Create tier definitions + self.tier_def_obj.create( + { + "model_id": self.tester_model.id, + "review_type": "individual", + "reviewer_id": self.test_user_2.id, + "definition_domain": "[('test_field', '>', 1.0)]", + "approve_sequence": True, + "has_forward": True, + "backward": True, + } + ) + # Request validation + review = test_record.sudo(user=self.test_user_2.id).request_validation() + self.assertTrue(review) + record = test_record.sudo(user=self.test_user_1.id) + record.invalidate_cache() + record.validate_tier() + self.assertFalse(record.can_forward) + self.assertFalse(record.can_backward) + # User 2 forward to user 1 + record = test_record.sudo(user=self.test_user_2.id) + record.invalidate_cache() + self.assertTrue(record.can_forward) + self.assertTrue(record.can_backward) + res = record.forward_tier() + ctx = res.get("context") + wizard = Form( + self.env["tier.validation.forward.wizard"] + .sudo(user=self.test_user_2.id) + .with_context(ctx) + ) + wizard.forward_reviewer_id = self.test_user_1 + wizard.forward_description = "Please review again" + wizard.backward = True + wiz = wizard.save() + wiz.add_forward() + # Newly created forwarded review will have no definition and will have origin + record = test_record.sudo(user=self.test_user_2.id) + record.invalidate_cache() + self.assertTrue(record.review_ids.filtered(lambda l: not l.definition_id)) + self.assertTrue(record.review_ids.filtered(lambda l: l.origin_id)) + # User 1 validate + res = record.sudo(user=self.test_user_1.id).validate_tier() + ctx = res.get("context") + wizard = Form( + self.env["comment.wizard"].sudo(user=self.test_user_1.id).with_context(ctx) + ) + wizard.comment = "Forward tier is reviewed" + wiz = wizard.save() + wiz.add_comment() + self.assertFalse(record.validated) + # Newly created review back to the original user + record = test_record.sudo(user=self.test_user_2.id) + record.invalidate_cache() + # There are now two tier reviews for user 2 + self.assertEqual( + len(record.review_ids.filtered( + lambda l: l.reviewer_id == self.test_user_2)), + 2 + ) + # User 2 does final validation + record.validate_tier() + self.assertTrue(record.validated) diff --git a/base_tier_validation_forward/views/tier_definition_view.xml b/base_tier_validation_forward/views/tier_definition_view.xml index dc46510f7e..1f64bad440 100644 --- a/base_tier_validation_forward/views/tier_definition_view.xml +++ b/base_tier_validation_forward/views/tier_definition_view.xml @@ -8,7 +8,20 @@ - + + + + + + + + Allow backward after the forward step is validated + diff --git a/base_tier_validation_forward/wizard/forward_wizard.py b/base_tier_validation_forward/wizard/forward_wizard.py index a778dac171..542a291df3 100644 --- a/base_tier_validation_forward/wizard/forward_wizard.py +++ b/base_tier_validation_forward/wizard/forward_wizard.py @@ -15,6 +15,37 @@ class ValidationForwardWizard(models.TransientModel): forward_description = fields.Char() has_comment = fields.Boolean(string="Allow Comment", default=True) approve_sequence = fields.Boolean(string="Approve by sequence", default=True,) + can_backward = fields.Boolean( + string="Can ask for review", + compute="_compute_can_backward" + ) + backward = fields.Boolean( + string="Ask for review", + default=False + ) + + def _compute_can_backward(self): + self.ensure_one() + record = self.env[self.res_model].browse(self.res_id) + self.can_backward = record.can_backward + + def _get_tier_review_data(self, rec, prev_review): + data = { + "name": self.forward_description, + "model": rec._name, + "res_id": rec.id, + "sequence": round(prev_review.sequence + 0.1, 2), + "requested_by": self.env.uid, + "review_type": "individual", + "reviewer_id": self.forward_reviewer_id.id, + "has_comment": self.has_comment, + "approve_sequence": self.approve_sequence, + } + if self.backward: + data.update({ + "origin_id": prev_review.id, + }) + return data def add_forward(self): """ Add extra step, with specific reviewer """ @@ -27,18 +58,9 @@ def add_forward(self): {"comment": _(">> %s") % self.forward_reviewer_id.display_name} ) prev_reviews = prev_comment.add_comment() + prev_review = prev_reviews.sorted("sequence")[-1:] # Get max sequence self.env["tier.review"].create( - { - "name": self.forward_description, - "model": rec._name, - "res_id": rec.id, - "sequence": max(prev_reviews.mapped("sequence")) + 0.1, - "requested_by": self.env.uid, - "review_type": "individual", - "reviewer_id": self.forward_reviewer_id.id, - "has_comment": self.has_comment, - "approve_sequence": self.approve_sequence, - } + self._get_tier_review_data(rec, prev_review) ) rec.invalidate_cache() rec.review_ids._compute_can_review() diff --git a/base_tier_validation_forward/wizard/forward_wizard_view.xml b/base_tier_validation_forward/wizard/forward_wizard_view.xml index 909bf60ded..a8aefc904f 100644 --- a/base_tier_validation_forward/wizard/forward_wizard_view.xml +++ b/base_tier_validation_forward/wizard/forward_wizard_view.xml @@ -12,9 +12,11 @@ + +