[16.0][MIG] account_payment_tier_validation: backport to v16#859
[16.0][MIG] account_payment_tier_validation: backport to v16#859
Conversation
dc3aa85 to
4aaf1b3
Compare
SirPyTech
left a comment
There was a problem hiding this comment.
Thanks for the PR!
Please check the migration process that is used in OCA for migrating to this major version: https://github.com/OCA/maintainer-tools/wiki/Migration-to-version-16.0.
This can be adapted to a backward-migration (like this one, from 18.0 to 16.0) adapting a few steps, for instance
git format-patch --keep-subject --stdout origin/16.0..origin/15.0 -- $module | git am -3 --keepin this case should be
git format-patch --keep-subject --stdout origin/16.0..origin/18.0 -- $module | git am -3 --keepAlso note that commits should be squashed according to https://github.com/OCA/maintainer-tools/wiki/Merge-commits-in-pull-requests.
Right now the commits are

and some of them should be squashed together.
Please fix the tests because right now they are failing:

If the CI fails then this PR can't be merged.
The first failure is:
2025-07-18 12:37:19,765 330 ERROR odoo odoo.addons.account_payment_line.tests.test_account_payment_line: FAIL: TestAccountPaymentLines.test_01_customer_payment
Traceback (most recent call last):
File "/__w/account-payment/account-payment/account_payment_line/tests/test_account_payment_line.py", line 201, in test_01_customer_payment
self.assertTrue(new_payment.is_reconciled)
AssertionError: False is not true
(from https://github.com/OCA/account-payment/actions/runs/16370675214/job/46258021642?pr=859#step:8:273)
I know it's not the module you are migrating, but if this PR is causing it to fail you have two options:
- (best) adapt the code so that it doesn't cause a failure in other modules
- mark both modules as not compatible and split the CI so that they are tested independently.
See https://github.com/OCA/oca-addons-repo-template/blob/d1483d585edc2323e8faba77c9294e5e2a4176b8/copier.yml#L147-L153:Are there in this repo modules that don't get along with their friends? If so, list them here (YAML format) and they will be tested in separate jobs.
Beware, if rebel modules should stay separated in groups, you should join them with commas, which could be misinterpreted by YAML.
Example: ["rebel_module_1,rebel_module_2", even_more_rebel_module]
You might want to look at related implementations like:
- account_payment_order_tier_validation for
16.0https://github.com/OCA/bank-payment/tree/4432cddb0c747298be581f71ec883197c19c7c94/account_payment_order_tier_validation - a previous attempt of implementing this same module: #664
|
|
||
| _tier_validation_manual_config = False | ||
|
|
||
| def action_post(self): |
There was a problem hiding this comment.
This method is overwriting core's method defined in https://github.com/odoo/odoo/blob/b0be89a67d0ce458db99f4331e21ed56d3c4774a/addons/account/models/account_payment.py#L934 without calling it with super, this breaks the inheritance chain.
Please add a call to super's method.
| "the recipient bank account must be manually validated. " | ||
| "You should go on the partner bank account of %(partner)s" | ||
| "in order to validate it.", | ||
| method_name=self.payment_method_line_id.name, |
There was a problem hiding this comment.
| method_name=self.payment_method_line_id.name, | |
| method_name=payment.payment_method_line_id.name, |
c534c8c to
d4bc558
Compare
|
Thank you @SirPyTech ! |
SirPyTech
left a comment
There was a problem hiding this comment.
chore: Please check again the commit history, right now it's

but according to https://github.com/OCA/maintainer-tools/wiki/Migration-to-version-16.0 it should be:
- All commits that come from
git format-patch(mentioned in #859 (review)), merged according to https://github.com/OCA/maintainer-tools/wiki/Merge-commits-in-pull-requests#mergesquash-the-commits-generated-by-bots-or-weblate - An automatic commit generated by
pre-commit - The
[MIG]commit with the needed manual changes to make the module work in16.0
Right now there are some commits after the [MIG] one that shouldn't be there.
@alexeirivera87 we are reviving your old PR #664, would you like to have a look?
There was a problem hiding this comment.
question: I don't think this file is needed in 16.0 (maybe not even in 18.0), could you please check and remove it eventually?
There was a problem hiding this comment.
Confirm, it's not needed. Removed.
|
|
||
| _tier_validation_manual_config = False | ||
|
|
||
| def action_post(self): |
| "the recipient bank account must be manually validated. " | ||
| "You should go on the partner bank account of %(partner)s" | ||
| "in order to validate it.", | ||
| method_name=self.payment_method_line_id.name, |
There was a problem hiding this comment.
chore: This file (and most of the module) is an almost exact copy of https://github.com/OCA/account-payment/pull/664/files#diff-9cef5e44f9cd3a54a978109fc6e89d61feb1d100206e820022a24efbf5e2a3ca, please at least add the author @alexeirivera87 as a co-author (see https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors) of the commit.
And I dare say they also deserve an author spot in the module itself.
There was a problem hiding this comment.
Of course, I've added Alexei as co-author in my last commit.
| _inherit = ["account.payment", "tier.validation"] | ||
| _state_from = ["draft"] | ||
| _state_to = ["posted"] | ||
| _cancel_state = "canceled" |
There was a problem hiding this comment.
suggestion: This is already declared in tier.validation (https://github.com/OCA/server-ux/blob/a6a3fb51c0f85f2031da1aba09328c1deb3b2fb4/base_tier_validation/models/tier_validation.py#L34), is it really needed here?
| class AccountPayment(models.Model): | ||
| _name = "account.payment" | ||
| _inherit = ["account.payment", "tier.validation"] | ||
| _state_from = ["draft"] |
There was a problem hiding this comment.
suggestion: This is already declared in tier.validation (https://github.com/OCA/server-ux/blob/a6a3fb51c0f85f2031da1aba09328c1deb3b2fb4/base_tier_validation/models/tier_validation.py#L32), is it really needed here?
| _cancel_state = "canceled" | ||
|
|
||
| _tier_validation_manual_config = False | ||
|
|
There was a problem hiding this comment.
question: comparing this file with https://github.com/OCA/account-payment/pull/664/files#diff-9cef5e44f9cd3a54a978109fc6e89d61feb1d100206e820022a24efbf5e2a3ca I see here we are missing the override of _get_under_validation_exceptions, was it causing any issues? Otherwise I'd say we can keep it.
There was a problem hiding this comment.
No issues keeping that method.
| def _get_need_validation(self): | ||
| """ | ||
| Needed because state is a related field not stored, | ||
| _compute_need_validation (field need_validation) in model | ||
| tier_validation, does not properly work when executing button | ||
| "Validate" | ||
| """ | ||
| self.ensure_one() | ||
| if isinstance(self.id, models.NewId): | ||
| return False | ||
| tiers = self.env["tier.definition"].search([("model", "=", self._name)]) | ||
| valid_tiers = any([self.evaluate_tier(tier) for tier in tiers]) | ||
| return ( | ||
| not self.review_ids | ||
| and valid_tiers | ||
| and self._context.get("validate_in_progress") | ||
| ) |
There was a problem hiding this comment.
suggestion: This is a slightly modified copy (the only change being the context usage) of an old version of _compute_need_validation (https://github.com/OCA/server-ux/blob/abf06d7e9365080987a2181205cbf017da736671/base_tier_validation/models/tier_validation.py#L216-L225):
def _compute_need_validation(self):
for rec in self:
if isinstance(rec.id, models.NewId):
rec.need_validation = False
continue
tiers = self.env["tier.definition"].search([("model", "=", self._name)])
valid_tiers = any([rec.evaluate_tier(tier) for tier in tiers])
rec.need_validation = (
not rec.review_ids and valid_tiers and rec._check_state_from_condition()
)Right now the code has been improved (https://github.com/OCA/server-ux/blob/a6a3fb51c0f85f2031da1aba09328c1deb3b2fb4/base_tier_validation/models/tier_validation.py#L251-L271):
def _compute_need_validation(self):
for rec in self:
if isinstance(rec.id, models.NewId):
rec.need_validation = False
continue
tiers = (
self.env["tier.definition"]
.with_context(active_test=True)
.search(
[
("model", "=", self._name),
("company_id", "in", [False] + rec._get_company().ids),
]
)
)
valid_tiers = tiers.filtered(lambda x: rec.evaluate_tier(x))
requested_tiers = rec.review_ids.filtered(
lambda x: x.status != "pending"
).mapped("definition_id")
new_tiers = valid_tiers - requested_tiers
rec.need_validation = new_tiers and rec._check_state_from_condition(), for instance with multi-company management, could you please update this code accordingly?
Or even better, we could try adding a depends_context to an override of _compute_need_validation so that we won't need to keep this copy updated, what do you think?
There was a problem hiding this comment.
I went with the update of the code, after several attempts to get override to work. As mentioned in docstring, _compute_need_validation in this case doesn't work properly, so I preferred to keep _get_need_validation, improved with multi-company management.
There was a problem hiding this comment.
That's fine, I understand it's not easy to adapt an override to work with the new context value.
But what about the last few lines of the above method?
valid_tiers = tiers.filtered(lambda x: rec.evaluate_tier(x))
requested_tiers = rec.review_ids.filtered(
lambda x: x.status != "pending"
).mapped("definition_id")
new_tiers = valid_tiers - requested_tiers
rec.need_validation = new_tiers and rec._check_state_from_condition()I see they are still missing in the latest code of this PR:
valid_tiers = tiers.filtered(lambda x: self.evaluate_tier(x))
return (
not self.review_ids
and valid_tiers
and self._context.get("validate_in_progress")
)There was a problem hiding this comment.
Here your reply from #859 (comment):
using the "new code", behavior changes and method doesn't work anymore as expected. No ValidationError is throwed so validation is always ok.
Looking at server-ux module, i saw that status field in tier.review in 18.0 has a new waiting selection, missing in 16.0. I did some attempts to fix behavior with new code but without success.
Anyway, all tests are ok and the behavior is the expected one, exactly as in v18.
What I am proposing has nothing to do with 18.0: the additional code has been added in 16.0 (where there is no waiting status`) with OCA/server-ux@a64e791, in the commit itself and its PR OCA/server-ux#928 you can find the reason behind it.
From a more generic point of view: the implementation in this model is kind of a needed hack for tier validation to work in a model where state field is related, so some of the usual methods in tier.validation do not get triggered properly.
The needed hack consists of using the context validate_in_progress to recognize when we need to validate the record: this is then used in places like _check_state_conditions_custom, while in tier.validation it is done in _check_state_conditions and _check_state_from_condition.
So this model has to re-implement all the places where such methods are used and:
- if there is
_check_state_from_conditionthen use the contextvalidate_in_progress - if there is
_check_state_conditionsthen use_check_state_conditions_custominstead
This has been done where needed: write and need_validation methods (see https://github.com/OCA/server-ux/blob/23e96d195dd78187789f42264a206350e470b01c/base_tier_validation/models/tier_validation.py).
As I suggested in #859 (comment), doing this with overrides would be more maintainable, but since it's technically harder, it's ok to copy/paste the methods.
If the copy-paste is not in sync (like in this piece of code), that would cause an unexpected behavior because payments validation would behave differently than any other tier-validated model (like invoices, when account_move_tier_validation is installed).
d4bc558 to
2b37547
Compare
SirPyTech
left a comment
There was a problem hiding this comment.
issue: The commits history looks duplicated:

Have a look at the 1st commit of this PR (b07ee98), the digest in the readme is 0baca...:
.
The first commits in 18.0 for this module are (note that they are in reversed order: latest one is above the others): 
According to https://github.com/OCA/maintainer-tools/wiki/Merge-commits-in-pull-requests they should all be merged together, so the digest of the resulting commit should be the one in the latest commit (7851a7e): 
That is: 6e4f14....
So the bot's commit has not been merged, it has been skipped.
I'm afraid other commits might be affected too, please have a look.
| _cancel_state = "canceled" | ||
|
|
||
| _tier_validation_manual_config = False | ||
|
|
| _inherit = ["account.payment", "tier.validation"] | ||
| _state_from = ["draft"] | ||
| _state_to = ["posted"] | ||
| _cancel_state = "canceled" |
| class AccountPayment(models.Model): | ||
| _name = "account.payment" | ||
| _inherit = ["account.payment", "tier.validation"] | ||
| _state_from = ["draft"] |
| def _get_need_validation(self): | ||
| """ | ||
| Needed because state is a related field not stored, | ||
| _compute_need_validation (field need_validation) in model | ||
| tier_validation, does not properly work when executing button | ||
| "Validate" | ||
| """ | ||
| self.ensure_one() | ||
| if isinstance(self.id, models.NewId): | ||
| return False | ||
| tiers = self.env["tier.definition"].search([("model", "=", self._name)]) | ||
| valid_tiers = any([self.evaluate_tier(tier) for tier in tiers]) | ||
| return ( | ||
| not self.review_ids | ||
| and valid_tiers | ||
| and self._context.get("validate_in_progress") | ||
| ) |
There was a problem hiding this comment.
That's fine, I understand it's not easy to adapt an override to work with the new context value.
But what about the last few lines of the above method?
valid_tiers = tiers.filtered(lambda x: rec.evaluate_tier(x))
requested_tiers = rec.review_ids.filtered(
lambda x: x.status != "pending"
).mapped("definition_id")
new_tiers = valid_tiers - requested_tiers
rec.need_validation = new_tiers and rec._check_state_from_condition()I see they are still missing in the latest code of this PR:
valid_tiers = tiers.filtered(lambda x: self.evaluate_tier(x))
return (
not self.review_ids
and valid_tiers
and self._context.get("validate_in_progress")
)| payment.amount = 100 | ||
| payment.action_post() | ||
| self.assertEqual(payment.state, "in_process") | ||
| self.assertEqual(payment.state, "draft") |
There was a problem hiding this comment.
question: Looks like the in_process status of 18.0 corresponds to the posted status in 16.0, so why is draft used here instead?
There was a problem hiding this comment.
Updated test using posted instead of draft (added also the two lines before in order to don't break tests.
There was a problem hiding this comment.
Can't reply to previous thread (_get_need_validation), so wrote response here: using the "new code", behavior changes and method doesn't work anymore as expected. No ValidationError is throwed so validation is always ok.
Looking at server-ux module, i saw that status field in tier.review in 18.0 has a new waiting selection, missing in 16.0. I did some attempts to fix behavior with new code but without success.
Anyway, all tests are ok and the behavior is the expected one, exactly as in v18.
There was a problem hiding this comment.
Can't reply to previous thread (
_get_need_validation)
The thread is #859 (comment)
There was a problem hiding this comment.
Updated test using
postedinstead ofdraft(added also the two lines before in order to don't break tests.
👍
2b37547 to
a4feb43
Compare
| def _get_need_validation(self): | ||
| """ | ||
| Needed because state is a related field not stored, | ||
| _compute_need_validation (field need_validation) in model | ||
| tier_validation, does not properly work when executing button | ||
| "Validate" | ||
| """ | ||
| self.ensure_one() | ||
| if isinstance(self.id, models.NewId): | ||
| return False | ||
| tiers = self.env["tier.definition"].search([("model", "=", self._name)]) | ||
| valid_tiers = any([self.evaluate_tier(tier) for tier in tiers]) | ||
| return ( | ||
| not self.review_ids | ||
| and valid_tiers | ||
| and self._context.get("validate_in_progress") | ||
| ) |
There was a problem hiding this comment.
Here your reply from #859 (comment):
using the "new code", behavior changes and method doesn't work anymore as expected. No ValidationError is throwed so validation is always ok.
Looking at server-ux module, i saw that status field in tier.review in 18.0 has a new waiting selection, missing in 16.0. I did some attempts to fix behavior with new code but without success.
Anyway, all tests are ok and the behavior is the expected one, exactly as in v18.
What I am proposing has nothing to do with 18.0: the additional code has been added in 16.0 (where there is no waiting status`) with OCA/server-ux@a64e791, in the commit itself and its PR OCA/server-ux#928 you can find the reason behind it.
From a more generic point of view: the implementation in this model is kind of a needed hack for tier validation to work in a model where state field is related, so some of the usual methods in tier.validation do not get triggered properly.
The needed hack consists of using the context validate_in_progress to recognize when we need to validate the record: this is then used in places like _check_state_conditions_custom, while in tier.validation it is done in _check_state_conditions and _check_state_from_condition.
So this model has to re-implement all the places where such methods are used and:
- if there is
_check_state_from_conditionthen use the contextvalidate_in_progress - if there is
_check_state_conditionsthen use_check_state_conditions_custominstead
This has been done where needed: write and need_validation methods (see https://github.com/OCA/server-ux/blob/23e96d195dd78187789f42264a206350e470b01c/base_tier_validation/models/tier_validation.py).
As I suggested in #859 (comment), doing this with overrides would be more maintainable, but since it's technically harder, it's ok to copy/paste the methods.
If the copy-paste is not in sync (like in this piece of code), that would cause an unexpected behavior because payments validation would behave differently than any other tier-validated model (like invoices, when account_move_tier_validation is installed).
| payment.amount = 100 | ||
| payment.action_post() | ||
| self.assertEqual(payment.state, "in_process") | ||
| self.assertEqual(payment.state, "draft") |
There was a problem hiding this comment.
Can't reply to previous thread (
_get_need_validation)
The thread is #859 (comment)
| payment.amount = 100 | ||
| payment.action_post() | ||
| self.assertEqual(payment.state, "in_process") | ||
| self.assertEqual(payment.state, "draft") |
There was a problem hiding this comment.
Updated test using
postedinstead ofdraft(added also the two lines before in order to don't break tests.
👍
a4feb43 to
89f0adc
Compare
|
Thank you Simone for the explanation. Now it's clearer for me, so I updated code. |
| def _get_need_validation(self): | ||
| """ | ||
| Needed because state is a related field not stored, | ||
| _compute_need_validation (field need_validation) in model | ||
| tier_validation, does not properly work when executing button | ||
| "Validate" | ||
| """ | ||
| self.ensure_one() | ||
| if isinstance(self.id, models.NewId): | ||
| return False | ||
| tiers = self.env["tier.definition"].search([("model", "=", self._name)]) | ||
| valid_tiers = any([self.evaluate_tier(tier) for tier in tiers]) | ||
| return ( | ||
| not self.review_ids | ||
| and valid_tiers | ||
| and self._context.get("validate_in_progress") | ||
| ) |
0ea9e0a to
939b696
Compare
|
After OCA/server-ux#1135, I had to change a couple of occurences of |
|
There hasn't been any activity on this pull request in the past 4 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 30 days. |
|
/ocabot merge nobump |
|
Hey, thanks for contributing! Proceeding to merge this for you. |
|
@rvalyi your merge command was aborted due to failed check(s), which you can inspect on this commit of 16.0-ocabot-merge-pr-859-by-rvalyi-bump-nobump. After fixing the problem, you can re-issue a merge command. Please refrain from merging manually as it will most probably make the target branch red. |
939b696 to
ed4ff70
Compare
|
Rebased to check merge failure |
Co-authored-by: Alexei Rivera <alexeirivera87@gmail.com>
ed4ff70 to
febdd7b
Compare
|
Fixed tests failure! |
|
This PR has the |
(from #859 (comment)) @rvalyi please try again |
|
Thanks for considering my old PR |
marcos-mendez
left a comment
There was a problem hiding this comment.
Automated Review -- Tests Failed
1. Root Cause
The test failure occurs because the account_payment_tier_validation module depends on base_tier_validation, which is not installed or available in the test environment. The error log shows that Odoo fails to load the registry due to a missing module dependency during button_install().
2. Suggested Fix
Ensure that base_tier_validation is included in the test environment or installed before running tests. In the __manifest__.py of account_payment_tier_validation, the dependency is correctly listed, but it seems the test setup (likely in odoo.tests.common.TransactionCase or similar) does not install the required modules.
Reference:
account_payment_tier_validation/__manifest__.pyline 15:"depends": ["account", "base_tier_validation"]- The test environment must ensure
base_tier_validationis installed prior to loadingaccount_payment_tier_validation.
3. Additional Code Issues
a. Incorrect use of self._get_company()
In account_payment.py, the method _get_need_validation() uses self._get_company() which may not be defined or may not return expected results for all contexts.
File: account_payment_tier_validation/models/account_payment.py
Method: _get_need_validation()
Lines: Around line 70–73
Issue:
self._get_company() is not a standard Odoo method. It should be replaced with self.company_id or self.env.company for consistency and correctness.
Fix suggestion:
Replace:
self._get_company().idswith:
self.company_id.idsb. Improper handling of NewId in _get_need_validation()
The check if isinstance(self.id, models.NewId): is correct, but the logic may not be robust enough for all edge cases in tier validation flow.
File: account_payment_tier_validation/models/account_payment.py
Method: _get_need_validation()
Lines: Around line 67–69
Suggestion:
Add explicit logging or validation to ensure that new records are not processed through tier validation logic unless explicitly required.
4. Test Improvements
a. Add TransactionCase Tests
Use TransactionCase to test full workflow including:
- Creation of payment
- Tier definition creation
- Validation request
- Review and confirmation
b. Test with SavepointCase for Isolation
Use SavepointCase to test:
- Tier validation behavior on existing vs new records
- Validation status changes during write operations
c. Tagged Tests
Tag tests appropriately using @tag('post_install') or @tag('tier_validation') to ensure proper execution order and filtering in CI.
d. Specific Test Scenarios
Add test cases for:
- Payment creation without tier definitions (should proceed normally)
- Payment creation with tier definitions (should require validation)
- Validation process with pending, rejected, and approved reviews
- Write operation behavior when validation is required or not
Example Test Snippet:
def test_payment_validation_flow(self):
# Create a tier definition for account.payment
tier_def = self.env['tier.definition'].create({
'model_id': self.env.ref('account.model_account_payment').id,
'definition_domain': [('amount', '>', 100)],
})
# Create a payment
payment = self.env['account.payment'].create({
'amount': 200,
'partner_id': self.env.ref('base.res_partner_1').id,
'journal_id': self.env.ref('account.cash_journal').id,
})
# Request validation
payment.action_request_validation()
self.assertTrue(payment.validation_status, 'pending')This ensures full coverage of the new logic and prevents regressions.
⚠️ PR Aging Alert: CRITICAL
This PR by @quirino95 has been waiting for 238 days — that is over 7 months without being merged or closed.
💤 No activity for 92 days. Has this PR been forgotten?
Every ignored PR is a contributor who might not come back. Review time matters. (OCA Aging Report)
Reciprocal Review Request
Hi everyone! I found some test failures on this PR and left detailed feedback above. I am happy to discuss or help debug. In the meantime, if any of you get a chance, I would appreciate a look at my open PR(s):
My open PRs across OCA:
- hr-attendance#262 [16.0][ADD] Hr_attendance_idsecure: iDSecure (ControliD) attendance integration
- stock-logistics-workflow#2276 [16.0][ADD] stock_move_line_devaluation
- stock-logistics-workflow#2275 [16.0][ADD] Stock move line analytic account
- stock-logistics-workflow#2268 [16.0][ADD] stock_move_line_picking_partner
- purchase-workflow#2694 [16.0][IMP]Purchase workflow added to review state & exception fix
Reviewing each other's work helps the whole community move forward. Thank you!
Environment via OCA Neural Reviewer: Minikube + K8s Job + oca-ci/py3.10-odoo16.0 | Odoo 16.0
Automated review by OCA Neural Reviewer + qwen3-coder:30b
|
/ocabot merge nobump |
|
This PR looks fantastic, let's merge it! |
|
@rvalyi your merge command was aborted due to failed check(s), which you can inspect on this commit of 16.0-ocabot-merge-pr-859-by-rvalyi-bump-nobump. After fixing the problem, you can re-issue a merge command. Please refrain from merging manually as it will most probably make the target branch red. |
|
@rvalyi your merge command was aborted due to failed check(s), which you can inspect on this commit of 16.0-ocabot-merge-pr-859-by-rvalyi-bump-nobump. After fixing the problem, you can re-issue a merge command. Please refrain from merging manually as it will most probably make the target branch red. |
|
Hi @OCA-git-bot, thank you for taking the time to respond to our automated review! Your feedback is valuable and helps us improve. We've logged this as an issue to review and improve our process: https://git.pop.coop/pop/oca-reviewer/issues/2 We'll work on addressing the points you raised. Auto-reply by oca-feedback |
Thanks you very much @rvalyi for trying to merge (ignoring AI review), the merge failed for the known issue mentioned in OCA/oca-addons-repo-template#333, we only have to update the repository template. |
No description provided.