diff --git a/base_tier_validation/README.rst b/base_tier_validation/README.rst index 64ed4c72..ca50c24d 100644 --- a/base_tier_validation/README.rst +++ b/base_tier_validation/README.rst @@ -80,6 +80,9 @@ To configure this module, you need to: Reject. - If check *Approve by sequence*, reviewers is forced to review by specified sequence. +- If check *Allow Bulk Approve*, reviewers can validate several reviews + at once from the Tier Review list. Reviews on definitions without this + flag are skipped from a bulk selection. To configure Tier Validation Exceptions, you need to: diff --git a/base_tier_validation/models/tier_definition.py b/base_tier_validation/models/tier_definition.py index b36a82f6..886a3d44 100644 --- a/base_tier_validation/models/tier_definition.py +++ b/base_tier_validation/models/tier_definition.py @@ -105,6 +105,12 @@ def _get_tier_validation_model_names(self): default=False, help="Approval order by the specified sequence number", ) + allow_bulk_approve = fields.Boolean( + default=False, + help="When set, reviewers can approve several reviews at once from the " + "tier review list view. Reviews whose definition does not have this " + "flag are skipped from a bulk selection.", + ) approve_sequence_bypass = fields.Boolean( help="Bypassed (auto validated), if previous tier was validated " "by same reviewer", diff --git a/base_tier_validation/models/tier_review.py b/base_tier_validation/models/tier_review.py index bed4caaf..fdfcbcd6 100644 --- a/base_tier_validation/models/tier_review.py +++ b/base_tier_validation/models/tier_review.py @@ -67,6 +67,7 @@ class TierReview(models.Model): approve_sequence_bypass = fields.Boolean( related="definition_id.approve_sequence_bypass" ) + allow_bulk_approve = fields.Boolean(related="definition_id.allow_bulk_approve") last_reminder_date = fields.Datetime(readonly=True) @api.depends("status") @@ -212,3 +213,53 @@ def _schedule_review_reminder_activity(self, record): note=self._notify_review_reminder_body(), user_id=self.reviewer_ids.id, ) + + def _filter_bulk_validatable(self): + """Return the subset of self that the current user may bulk-approve. + + A review is eligible when its definition opts in via + ``allow_bulk_approve``, the review is pending and assigned to the + current user, the user is the reviewer-of-the-moment (``can_review``), + and the definition does not require a per-review comment (which + cannot be collected in a bulk action). + """ + return self.filtered( + lambda r: r.allow_bulk_approve + and r.status == "pending" + and r.can_review + and self.env.user in r.reviewer_ids + and not r.has_comment + ) + + def action_bulk_validate(self): + """Approve every eligible review in ``self`` in a single call. + + Reviews are grouped by their underlying record so that each record's + own ``_validate_tier`` runs once -- preserving notifications, the + approve-sequence promotion logic, and the review counter update. + Ineligible reviews are skipped silently; the action is meant to be + wired to the list view header. + """ + eligible = self._filter_bulk_validatable() + if not eligible: + return False + by_key = {} + for review in eligible: + by_key.setdefault((review.model, review.res_id), self.browse()) + by_key[(review.model, review.res_id)] |= review + validated = {} + for (model, res_id), reviews in by_key.items(): + record = self.env[model].browse(res_id) + record._validate_tier(reviews) + validated[model] = validated.get(model, record.browse()) | record + # Update the counter once for the whole batch, not once per record. + # ``_update_counter`` re-promotes the remaining reviews and pushes a + # bus notification, and the systray answers every notification with a + # recount of its badge. Per record, approving a selection of N + # documents fans out to N notifications per reviewer -- multiplied by + # each reviewer's open tabs -- which is exactly the pattern bulk + # approve is meant to make routine. Batched, the selection costs one + # notification per reviewer however large it is. + for records in validated.values(): + records._update_counter({"review_deleted": True}) + return True diff --git a/base_tier_validation/readme/CONFIGURE.md b/base_tier_validation/readme/CONFIGURE.md index 4bd817e6..944fc755 100644 --- a/base_tier_validation/readme/CONFIGURE.md +++ b/base_tier_validation/readme/CONFIGURE.md @@ -15,6 +15,9 @@ To configure this module, you need to: Reject. - If check *Approve by sequence*, reviewers is forced to review by specified sequence. +- If check *Allow Bulk Approve*, reviewers can validate several reviews at + once from the Tier Review list. Reviews on definitions without this flag + are skipped from a bulk selection. To configure Tier Validation Exceptions, you need to: diff --git a/base_tier_validation/static/description/index.html b/base_tier_validation/static/description/index.html index 3a8f165f..7a89a1be 100644 --- a/base_tier_validation/static/description/index.html +++ b/base_tier_validation/static/description/index.html @@ -446,6 +446,9 @@
To configure Tier Validation Exceptions, you need to: