Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[17.0][IMP] base_tier_validation: Merge module with base_tier_validation_waiting #800

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions base_tier_validation/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ To configure this module, you need to:

- If check *Notify Reviewers on Creation*, all possible reviewers will
be notified by email when this definition is triggered.
- If check *Notify reviewers on reaching pending* if you want to send a
notification when pending status is reached. This is usefull in a
approve by sequence scenario to only notify reviewers when it is
their turn in the sequence.
- If check *Comment*, reviewers can comment after click Validate or
Reject.
- If check *Approve by sequence*, reviewers is forced to review by
Expand Down Expand Up @@ -96,6 +100,13 @@ improvement will be very valuable.
Changelog
=========

17.0.1.0.0 (2024-01-10)
-----------------------

Migrated to Odoo 17. Merged module with tier_validation_waiting. To
support sending messages in a validation sequence when it is their turn
to validate.

14.0.1.0.0 (2020-11-19)
-----------------------

Expand Down Expand Up @@ -206,6 +217,7 @@ Credits
Authors
-------

* brain-tec AG
* ForgeFlow

Contributors
Expand All @@ -219,6 +231,8 @@ Contributors
- Kitti U. <kittiu@ecosoft.co.th>
- Saran Lim. <saranl@ecosoft.co.th>
- Carlos Lopez <celm1990@gmail.com>
- Javier Colmeiro <javier.colmeiro@braintec.com>
- bosd

Maintainers
-----------
Expand Down
2 changes: 1 addition & 1 deletion base_tier_validation/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"maintainers": ["LoisRForgeFlow"],
"category": "Tools",
"website": "https://github.com/OCA/server-ux",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"author": "brain-tec AG, ForgeFlow, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
Expand Down
7 changes: 7 additions & 0 deletions base_tier_validation/models/tier_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ def _get_tier_validation_model_names(self):
help="If set, all possible reviewers will be notified by email when "
"this definition is triggered.",
)
notify_on_pending = fields.Boolean(
string="Notify Reviewers on reaching Pending",
help="If set, all possible reviewers will be notified by email when "
"this status is reached."
"Usefull in an Approve by sequence scenario. "
"An notification request to review is sent out when it's their turn to review.",
)
has_comment = fields.Boolean(string="Comment", default=False)
approve_sequence = fields.Boolean(
string="Approve by sequence",
Expand Down
27 changes: 24 additions & 3 deletions base_tier_validation/models/tier_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ class TierReview(models.Model):

name = fields.Char(related="definition_id.name", readonly=True)
status = fields.Selection(
selection=[
[
("waiting", "Waiting"),
("pending", "Pending"),
("rejected", "Rejected"),
("approved", "Approved"),
],
default="pending",
default="waiting",
)
model = fields.Char(string="Related Document Model", index=True)
res_id = fields.Integer(string="Related Document ID", index=True)
Expand Down Expand Up @@ -77,11 +78,26 @@ def _compute_reviewed_formated_date(self):

@api.depends("definition_id.approve_sequence")
def _compute_can_review(self):
reviews = self.filtered(lambda rev: rev.status in ["waiting", "pending"])
if reviews:
# get minimum sequence of all to prevent jumps
next_seq = min(reviews.mapped("sequence"))
for record in reviews:
# if approve by sequence, check sequence has been reached
if record.approve_sequence:
if record.sequence == next_seq:
record.status = "pending"
# if there is no approval sequence go directly to pending state
elif not record.approve_sequence:
record.status = "pending"
if record.status == "pending":
if record.definition_id.notify_on_pending:
record._notify_pending_status(record)
Comment on lines +81 to +95
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm uncertain whether it's advisable to update fields within a computed function if those fields are not explicitly defined as computed (field status).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: Please let me know your comments regarding my comment on computed fields not being defined as computed explicitly. Could this be causing cache inconsistency?

tbh, I'm a bit overasked by this..
Maybe it is not the ideal situation. (yet, I'm unaware of any alternative method to implement this).
Well, we've deployed this code succesfully in production. W/o any problems.
Judging from the experience it is okay..
But happy to learn from the more experienced dev's.

for record in self:
record.can_review = record._can_review_value()

def _can_review_value(self):
if self.status != "pending":
if self.status not in ("pending", "waiting"):
return False
if not self.approve_sequence:
return True
Expand Down Expand Up @@ -126,3 +142,8 @@ def _get_reviewers(self):
if not reviewer_field or not reviewer_field._name == "res.users":
raise ValidationError(_("There are no res.users in the selected field"))
return reviewer_field

def _notify_pending_status(self, review_ids):
"""Method to call and reuse abstract notification method"""
resource = self.env[self.model].browse(self.res_id)
resource._notify_review_available(review_ids)
69 changes: 59 additions & 10 deletions base_tier_validation/models/tier_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ class TierValidation(models.AbstractModel):
_state_to = ["confirmed"]
_cancel_state = "cancel"

# TODO: step by step validation?

review_ids = fields.One2many(
comodel_name="tier.review",
inverse_name="res_id",
Expand All @@ -47,6 +45,7 @@ class TierValidation(models.AbstractModel):
validation_status = fields.Selection(
selection=[
("no", "Without validation"),
("waiting", "Waiting"),
("pending", "Pending"),
("rejected", "Rejected"),
("validated", "Validated"),
Expand All @@ -70,12 +69,15 @@ class TierValidation(models.AbstractModel):
def _compute_has_comment(self):
for rec in self:
has_comment = rec.review_ids.filtered(
lambda r: r.status == "pending" and (self.env.user in r.reviewer_ids)
lambda r: r.status in ("waiting", "pending")
and self.env.user in r.reviewer_ids
).mapped("has_comment")
rec.has_comment = True in has_comment

def _get_sequences_to_approve(self, user):
all_reviews = self.review_ids.filtered(lambda r: r.status == "pending")
all_reviews = self.review_ids.filtered(
lambda r: r.status in ("waiting", "pending")
)
my_reviews = all_reviews.filtered(lambda r: user in r.reviewer_ids)
# Include all my_reviews with approve_sequence = False
sequences = my_reviews.filtered(lambda r: not r.approve_sequence).mapped(
Expand All @@ -98,7 +100,7 @@ def _compute_can_review(self):
def _search_can_review(self, operator, value):
domain = [
("review_ids.reviewer_ids", "=", self.env.user.id),
("review_ids.status", "=", "pending"),
("review_ids.status", "in", ["pending", "waiting"]),
("review_ids.can_review", "=", True),
("rejected", "=", False),
]
Expand All @@ -111,7 +113,7 @@ def _search_can_review(self, operator, value):
def _compute_reviewer_ids(self):
for rec in self:
rec.reviewer_ids = rec.review_ids.filtered(
lambda r: r.status == "pending"
lambda r: r.status in ("waiting", "pending")
).mapped("reviewer_ids")

@api.model
Expand Down Expand Up @@ -145,7 +147,6 @@ def _search_reviewer_ids(self, operator, value):
("model", "=", self._name),
("reviewer_ids", operator, value),
("can_review", "=", True),
("status", "=", "pending"),
]
)
return [("id", model_operator, list(set(reviews.mapped("res_id"))))]
Expand Down Expand Up @@ -192,6 +193,12 @@ def _compute_validation_status(self):
and any(item.review_ids.filtered(lambda x: x.status == "pending"))
):
item.validation_status = "pending"
elif (
not item.validated
and not item.rejected
and any(item.review_ids.filtered(lambda x: x.status == "waiting"))
):
item.validation_status = "waiting"
else:
item.validation_status = "no"

Expand Down Expand Up @@ -320,6 +327,20 @@ def _check_state_conditions(self, vals):
def _validate_tier(self, tiers=False):
self.ensure_one()
tier_reviews = tiers or self.review_ids
waiting_reviews = tier_reviews.filtered(
lambda r: r.status == "waiting"
or r.approve_sequence_bypass
and self.env.user in r.reviewer_ids
)
if waiting_reviews:
waiting_reviews.write(
{
"status": "pending",
"done_by": self.env.user.id,
"reviewed_date": fields.Datetime.now(),
}
)

user_reviews = tier_reviews.filtered(
lambda r: r.status == "pending" and (self.env.user in r.reviewer_ids)
)
Expand Down Expand Up @@ -427,7 +448,8 @@ def _rejected_tier(self, tiers=False):
self.ensure_one()
tier_reviews = tiers or self.review_ids
user_reviews = tier_reviews.filtered(
lambda r: r.status == "pending" and (self.env.user in r.reviewer_ids)
lambda r: r.status in ("waiting", "pending")
and self.env.user in r.reviewer_ids
)
user_reviews.write(
{
Expand All @@ -440,10 +462,16 @@ def _rejected_tier(self, tiers=False):
rec = self.env[review.model].browse(review.res_id)
rec._notify_rejected_review()

def _notify_created_review_body(self):
return _("A record to be reviewed has been created by %s.") % (
self.env.user.name
)

def _notify_requested_review_body(self):
return _("A review has been requested by %s.") % (self.env.user.name)

def _notify_review_requested(self, tier_reviews):
"""method to notify when tier validation is created"""
subscribe = "message_subscribe"
post = "message_post"
if hasattr(self, post) and hasattr(self, subscribe):
Expand All @@ -459,7 +487,7 @@ def _notify_review_requested(self, tier_reviews):
)
getattr(rec, post)(
subtype_xmlid=self._get_requested_notification_subtype(),
body=rec._notify_requested_review_body(),
body=rec._notify_created_review_body(),
)

def _prepare_tier_review_vals(self, definition, sequence):
Expand Down Expand Up @@ -509,7 +537,9 @@ def restart_validation(self):
for rec in self:
if getattr(rec, self._state_field) in self._state_from:
to_update_counter = (
rec.mapped("review_ids").filtered(lambda a: a.status == "pending")
rec.mapped("review_ids").filtered(
lambda a: a.status in ("waiting", "pending")
)
and True
or False
)
Expand Down Expand Up @@ -594,3 +624,22 @@ def get_view(self, view_id=None, view_type="form", **options):
res["arch"] = etree.tostring(doc)
res["models"] = frozendict(all_models)
return res

def _notify_review_available(self, tier_reviews):
"""method to notify when reaching pending"""
subscribe = "message_subscribe"
post = "message_post"
if hasattr(self, post) and hasattr(self, subscribe):
for rec in self.sudo():
users_to_notify = tier_reviews.filtered(
lambda r, x=rec: r.definition_id.notify_on_pending
and r.res_id == x.id
).mapped("reviewer_ids")
# Subscribe reviewers and notify
rec.message_subscribe(
partner_ids=users_to_notify.mapped("partner_id").ids
)
rec.message_post(
subtype_xmlid=self._get_requested_notification_subtype(),
body=rec._notify_requested_review_body(),
)
2 changes: 2 additions & 0 deletions base_tier_validation/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ To configure this module, you need to:

- If check *Notify Reviewers on Creation*, all possible reviewers will
be notified by email when this definition is triggered.
- If check *Notify reviewers on reaching pending* if you want to send a notification when pending status is reached.
This is usefull in a approve by sequence scenario to only notify reviewers when it is their turn in the sequence.
- If check *Comment*, reviewers can comment after click Validate or
Reject.
- If check *Approve by sequence*, reviewers is forced to review by
Expand Down
2 changes: 2 additions & 0 deletions base_tier_validation/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
- Kitti U. \<<kittiu@ecosoft.co.th>\>
- Saran Lim. \<<saranl@ecosoft.co.th>\>
- Carlos Lopez \<<celm1990@gmail.com>\>
- Javier Colmeiro \<<javier.colmeiro@braintec.com>\>
- bosd
6 changes: 6 additions & 0 deletions base_tier_validation/readme/HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 17.0.1.0.0 (2024-01-10)

Migrated to Odoo 17.
Merged module with tier_validation_waiting.
To support sending messages in a validation sequence when it is their turn to validate.

## 14.0.1.0.0 (2020-11-19)

Migrated to Odoo 14.
Expand Down
Loading
Loading