details: https://code.tryton.org/tryton/commit/2fc55f35f172
branch: default
user: Cédric Krier <[email protected]>
date: Wed Apr 08 17:16:26 2026 +0200
description:
Limit the application of receivable rules to accounts and parties in
the statement
Closes #14755
diffstat:
modules/account_receivable_rule/account.py | 35 ++++++++++++++++++-----------
1 files changed, 22 insertions(+), 13 deletions(-)
diffs (93 lines):
diff -r f40552d29378 -r 2fc55f35f172 modules/account_receivable_rule/account.py
--- a/modules/account_receivable_rule/account.py Wed Apr 08 14:42:10
2026 +0200
+++ b/modules/account_receivable_rule/account.py Wed Apr 08 17:16:26
2026 +0200
@@ -1,6 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
+from collections import defaultdict
from sql import Literal, Null
from sql.aggregate import Sum
@@ -124,7 +125,7 @@
@dualmethod
@ModelView.button
- def apply(cls, rules=None):
+ def apply(cls, rules=None, parties=None, rules_parties=None):
pool = Pool()
User = pool.get('res.user')
Move = pool.get('account.move')
@@ -134,11 +135,12 @@
('company', '=', company.id),
])
moves = []
- for rule in rules:
- moves.extend(rule._apply())
+ for rules, parties in [(rules, parties), *(rules_parties or [])]:
+ for rule in rules:
+ moves.extend(rule._apply(parties=parties))
Move.post(moves)
- def _apply(self):
+ def _apply(self, parties=None):
pool = Pool()
Move = pool.get('account.move')
Line = pool.get('account.move.line')
@@ -147,7 +149,7 @@
lines = []
to_reconcile = []
to_reconcile_delegate = []
- for party, amount in self._amounts():
+ for party, amount in self._amounts(parties=parties):
for line in self._lines_to_reconcile(party):
line_amount = -self._amount(line)
account_rule = self.get_account_rule(line.account)
@@ -281,7 +283,7 @@
]
return move, lines
- def _amounts(self):
+ def _amounts(self, parties=None):
"Yield party id and amount to dispatch"
pool = Pool()
Line = pool.get('account.move.line')
@@ -291,15 +293,19 @@
cursor = Transaction().connection.cursor()
amount = Sum(self._amount(line))
+ where = (
+ (line.account == self.account.id)
+ & (line.reconciliation == Null)
+ & (move.state == 'posted'))
+ if parties is not None:
+ where &= fields.SQL_OPERATORS['in'](
+ line.party, [p.id for p in parties])
query = (line
.join(move, condition=line.move == move.id)
.select(
line.party,
amount.as_('amount'),
- where=(
- (line.account == self.account.id)
- & (line.reconciliation == Null)
- & (move.state == 'posted')),
+ where=where,
group_by=line.party,
having=amount > 0))
if backend.name == 'sqlite':
@@ -459,8 +465,11 @@
pool = Pool()
Rule = pool.get('account.account.receivable.rule')
super().post(statements)
- rules = set()
+ accounts = defaultdict(set)
for statement in statements:
for line in statement.lines:
- rules.update(line.account.receivable_rules)
- Rule.apply(Rule.browse(rules))
+ if line.account.receivable_rules:
+ accounts[line.account].add(line.party)
+ rules_parties = [(a.receivable_rules, p) for a, p in accounts.items()]
+ if rules_parties:
+ Rule.apply(*rules_parties[0], rules_parties[1:])