diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py index ec40bc60af..e84ea57429 100644 --- a/base_tier_validation/models/tier_definition.py +++ b/base_tier_validation/models/tier_definition.py @@ -62,6 +62,15 @@ def _get_tier_validation_model_names(self): string="Company", default=lambda self: self.env.company, ) + subscription_mode = fields.Selection( + [ + ("standard", "Standard subscription mode"), + ("tier_validation", "Subscribe only to Tier Validation notifications"), + ], + default="standard", + required=True, + change_default=True, + ) notify_on_create = fields.Boolean( string="Notify Reviewers on Creation", help="If set, all possible reviewers will be notified by email when " @@ -79,8 +88,8 @@ def _get_tier_validation_model_names(self): ) notify_on_restarted = fields.Boolean( string="Notify Reviewers on Restarted", - help="If set, reviewers will be notified by email when a reviews related " - "to this definition are restarted.", + help="If set, reviewers will be notified by email when a review related " + "to this definition is restarted.", ) has_comment = fields.Boolean(string="Comment", default=False) approve_sequence = fields.Boolean( diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py index 8d2bef8870..5dcedf96bf 100644 --- a/base_tier_validation/models/tier_validation.py +++ b/base_tier_validation/models/tier_validation.py @@ -423,6 +423,20 @@ def _check_state_conditions(self, vals): and vals.get(self._state_field) in self._state_to ) + def _notify_review_accepted(self, tier_reviews): + subscribe = "message_subscribe" + post = "message_post" + if hasattr(self, post) and hasattr(self, subscribe): + reviews_to_notify = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_accepted + ) + if reviews_to_notify: + self._subscribe_review(tier_reviews) + getattr(self.sudo(), post)( + subtype_xmlid=self._get_accepted_notification_subtype(), + body=self._notify_accepted_reviews_body(), + ) + def _validate_tier(self, tiers=False): self.ensure_one() tier_reviews = tiers or self.review_ids @@ -436,20 +450,55 @@ def _validate_tier(self, tiers=False): "reviewed_date": fields.Datetime.now(), } ) - reviews_to_notify = user_reviews.filtered( - lambda r: r.definition_id.notify_on_accepted + self._notify_review_accepted(user_reviews) + + def _subscribe_review(self, tier_reviews): + subtype_ids = self._get_notification_subtypes(tier_reviews) + partners_to_notify_ids = self._get_partners_to_notify(tier_reviews, subtype_ids) + if subtype_ids is None or subtype_ids: + self.message_subscribe( + partner_ids=partners_to_notify_ids, + subtype_ids=subtype_ids, + ) + + def _get_partners_to_notify(self, tier_reviews, subtype_ids): + if subtype_ids: + partner_ids = list( + set(tier_reviews.mapped("reviewer_ids.partner_id.id")) + - set(self.mapped("message_follower_ids.partner_id.id")) + ) + else: + partner_ids = tier_reviews.mapped("reviewer_ids.partner_id.id") + return partner_ids + + def _get_notification_subtypes(self, tier_reviews): + subtype_ids = self.env["mail.message.subtype"] + default_subscription_mode = tier_reviews.filtered( + lambda x: "standard" in x.definition_id.subscription_mode + ) + if default_subscription_mode: + return None + notify_on_create = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_create and r.res_id == self.id ) - if reviews_to_notify: - subscribe = "message_subscribe" - if hasattr(self, subscribe): - getattr(self, subscribe)( - partner_ids=reviews_to_notify.mapped("reviewer_ids") - .mapped("partner_id") - .ids - ) - for review in reviews_to_notify: - rec = self.env[review.model].browse(review.res_id) - rec._notify_accepted_reviews() + if notify_on_create: + subtype_ids += self.env.ref(self._get_requested_notification_subtype()) + notify_on_accepted = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_accepted and r.res_id == self.id + ) + if notify_on_accepted: + subtype_ids += self.env.ref(self._get_accepted_notification_subtype()) + notify_on_rejected = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_rejected and r.res_id == self.id + ) + if notify_on_rejected: + subtype_ids += self.env.ref(self._get_rejected_notification_subtype()) + notify_on_restarted = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_restarted and r.res_id == self.id + ) + if notify_on_restarted: + subtype_ids += self.env.ref(self._get_restarted_notification_subtype()) + return subtype_ids.ids def _get_requested_notification_subtype(self): return "base_tier_validation.mt_tier_validation_requested" @@ -534,14 +583,19 @@ def _notify_rejected_review_body(self): } return _("A review was rejected by %s.") % (self.env.user.name) - def _notify_rejected_review(self): + def _notify_rejected_review(self, tier_reviews): + subscribe = "message_subscribe" post = "message_post" - if hasattr(self, post): - # Notify state change - getattr(self.sudo(), post)( - subtype_xmlid=self._get_rejected_notification_subtype(), - body=self._notify_rejected_review_body(), + if hasattr(self, post) and hasattr(self, subscribe): + reviews_to_notify = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_rejected ) + if reviews_to_notify: + self.sudo()._subscribe_review(tier_reviews) + getattr(self.sudo(), post)( + subtype_xmlid=self._get_rejected_notification_subtype(), + body=self._notify_rejected_review_body(), + ) def _rejected_tier(self, tiers=False): self.ensure_one() @@ -556,21 +610,7 @@ def _rejected_tier(self, tiers=False): "reviewed_date": fields.Datetime.now(), } ) - - reviews_to_notify = user_reviews.filtered( - lambda r: r.definition_id.notify_on_rejected - ) - if reviews_to_notify: - subscribe = "message_subscribe" - if hasattr(self, subscribe): - getattr(self, subscribe)( - partner_ids=reviews_to_notify.mapped("reviewer_ids") - .mapped("partner_id") - .ids - ) - for review in reviews_to_notify: - rec = self.env[review.model].browse(review.res_id) - rec._notify_rejected_review() + self._notify_rejected_review(user_reviews) def _notify_requested_review_body(self): return _("A review has been requested by %s.") % (self.env.user.name) @@ -580,14 +620,11 @@ def _notify_review_requested(self, tier_reviews): post = "message_post" if hasattr(self, post) and hasattr(self, subscribe): for rec in self.sudo(): - users_to_notify = tier_reviews.filtered( - lambda r: r.definition_id.notify_on_create and r.res_id == rec.id - ).mapped("reviewer_ids") - # Subscribe reviewers and notify - if len(users_to_notify) > 0: - getattr(rec, subscribe)( - partner_ids=users_to_notify.mapped("partner_id").ids - ) + reviews_to_notify = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_create + ) + if reviews_to_notify: + rec._subscribe_review(tier_reviews) getattr(rec, post)( subtype_xmlid=self._get_requested_notification_subtype(), body=rec._notify_requested_review_body(), @@ -629,42 +666,30 @@ def _notify_restarted_review_body(self): return _("The review has been reset by %s.") % (self.env.user.name) def _notify_restarted_review(self): + subscribe = "message_subscribe" post = "message_post" - if hasattr(self, post): - getattr(self.sudo(), post)( - subtype_xmlid=self._get_restarted_notification_subtype(), - body=self._notify_restarted_review_body(), + if hasattr(self, post) and hasattr(self, subscribe): + tier_reviews = self.mapped("review_ids") + reviews_to_notify = tier_reviews.filtered( + lambda r: r.definition_id.notify_on_restarted ) + if reviews_to_notify: + self._subscribe_review(tier_reviews) + getattr(self.sudo(), post)( + subtype_xmlid=self._get_restarted_notification_subtype(), + body=self._notify_restarted_review_body(), + ) def restart_validation(self): for rec in self: - partners_to_notify_ids = False if getattr(rec, self._state_field) in self._state_from: - to_update_counter = ( - rec.mapped("review_ids").filtered(lambda a: a.status == "pending") - and True - or False + to_update_counter = rec.mapped("review_ids").filtered( + lambda a: a.status == "pending" ) - reviews_to_notify = rec.review_ids.filtered( - lambda r: r.definition_id.notify_on_restarted - ) - if reviews_to_notify: - partners_to_notify_ids = ( - reviews_to_notify.mapped("reviewer_ids") - .mapped("partner_id") - .ids - ) - rec.mapped("review_ids").unlink() if to_update_counter: self._update_counter({"review_deleted": True}) - if partners_to_notify_ids: - subscribe = "message_subscribe" - reviews_to_notify = rec.review_ids.filtered( - lambda r: r.definition_id.notify_on_restarted - ) - if hasattr(self, subscribe): - getattr(self, subscribe)(partner_ids=partners_to_notify_ids) rec._notify_restarted_review() + rec.mapped("review_ids").unlink() @api.model def _update_counter(self, review_counter): diff --git a/base_tier_validation/tests/test_tier_validation.py b/base_tier_validation/tests/test_tier_validation.py index 1ea79580c8..1fac466be1 100644 --- a/base_tier_validation/tests/test_tier_validation.py +++ b/base_tier_validation/tests/test_tier_validation.py @@ -905,6 +905,85 @@ def test_25_change_field_exception_validation(self): ) self.assertEqual(self.test_record.test_validation_field, 4) + def test_26_notify_only_tier_validation(self): + tier_definition = self.env["tier.definition"].search([]) + tier_definition.write( + { + "subscription_mode": "standard", + "notify_on_create": True, + "notify_on_accepted": True, + "notify_on_rejected": True, + "notify_on_restarted": True, + "review_type": "group", + "reviewer_group_id": self.env.ref("base.group_system").id, + } + ) + # notify on create + test_record_1 = self.test_model.create({"test_field": 2.5}) + notifications_no_1 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + test_record_1.request_validation() + notifications_no_2 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + self.assertEqual(notifications_no_2, notifications_no_1 + 1) + + # notify on message post + notifications_no_1 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + test_record_1.message_post( + body="Message post on test_record.", + subtype_id=self.env.ref("mail.mt_comment").id, + ) + notifications_no_2 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + self.assertEqual(notifications_no_2, notifications_no_1 + 1) + + tier_definition.write({"subscription_mode": "tier_validation"}) + + # notify on create + test_record_2 = self.test_model.create({"test_field": 2.5}) + notifications_no_1 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + test_record_2.request_validation() + notifications_no_2 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + self.assertEqual(notifications_no_2, notifications_no_1 + 1) + + # do not notify on message post + notifications_no_1 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + test_record_2.message_post( + body="Message post on test_record.", + subtype_id=self.env.ref("mail.mt_comment").id, + ) + notifications_no_2 = len( + self.env["mail.notification"].search( + [("res_partner_id", "=", self.test_user_1.partner_id.id)] + ) + ) + self.assertEqual(notifications_no_2, notifications_no_1) + @tagged("at_install") class TierTierValidationView(CommonTierValidation): diff --git a/base_tier_validation/views/tier_definition_view.xml b/base_tier_validation/views/tier_definition_view.xml index 19728d4ae4..594b352963 100644 --- a/base_tier_validation/views/tier_definition_view.xml +++ b/base_tier_validation/views/tier_definition_view.xml @@ -98,6 +98,7 @@ +