fix: target actual bank.rec.widget (OWL) instead of legacy reconciliation widget — implement rest_debit/rest_credit fields + template extension

This commit is contained in:
Kristof Bernaert
2026-08-10 20:50:58 +02:00
parent 2a99ecbe5b
commit 277b38a0e9
7 changed files with 105 additions and 94 deletions
@@ -2,15 +2,15 @@
## Overview
`dlv_account_reconciliation_rest_amount` extends the standard bank
reconciliation screen (Accounting → Reconciliation) so the still-open
("rest") amount of a line is shown in parentheses next to its total.
`dlv_account_reconciliation_rest_amount` extends the bank reconciliation
widget (Accounting → Reconciliation, model `bank.rec.widget`) so the still
outstanding ("rest") amount of a partially matched line is shown in
parentheses next to its total.
On the reconciliation screen, when a proposed line (the bank movement itself,
or an added invoice/bill) is only partially used to close the statement line,
Odoo shows the full amount struck through and the partial amount used above
it — but not what remains unmatched on that line. This addon adds that
missing number, e.g.:
On the reconciliation screen, when an added invoice/bill (a `new_aml` line)
is only partially used to close the statement line, Odoo shows the full
source amount struck through below the amount actually used — but not what
remains unmatched on that line. This addon adds that missing number, e.g.:
```
€ 1.899,97
@@ -22,19 +22,27 @@ outstanding, without having to search for it elsewhere.
## How it works
- `static/src/js/reconciliation_rest_amount.js` patches
`account.ReconciliationRenderer`'s `ManualLineRenderer.update()`. Before
every render, it walks `state.reconciliation_proposition` and, for any line
where `partial_amount` differs from `amount`, computes and formats the
difference as `line.rest_amount_str`.
- `static/src/xml/reconciliation_rest_amount.xml` inherits the shared
`reconciliation.line.mv_line.amount` template (from `account_accountant`)
via xpath and prints `line.rest_amount_str` between parentheses, right
after the existing amount.
- `models/bank_rec_widget_line.py` inherits `bank.rec.widget.line` and adds
two computed `Monetary` fields, `rest_debit` and `rest_credit`
(`source_balance - balance`, split like the existing `debit`/`credit`
fields). Because `bank.rec.widget._compute_lines_widget` automatically
serializes every field of `bank.rec.widget.line` to the front-end, these
two fields become available client-side as `line.rest_debit` /
`line.rest_credit` (each with `.display`, `.value`, `.is_zero`) with no
extra plumbing needed.
- `static/src/xml/reconciliation_rest_amount.xml` extends the OWL template
`account_accountant.bank_rec_widget_form_lines_widget`
(`t-inherit-mode="extension"`) and prints the rest amount in parentheses
next to the struck-through source amount, when it is non-zero.
Because both the bank movement (liquidity line) and any added invoice/bill
proposition are rendered through the same loop and template, this single
patch covers both cases.
### Note on the bank movement itself
Earlier iterations of this addon assumed the bank movement (liquidity) line
could also show a "rest" amount, based on the legacy (pre-16.4) reconciliation
widget where that concept existed. In the `bank.rec.widget` model actually
used on this instance, the liquidity line always reflects the full statement
line amount — there is no partial/rest concept for it, so nothing is shown
there. See ROADMAP.md.
## Dependencies
@@ -42,5 +50,6 @@ patch covers both cases.
## Installation
Standard addon install/update. No configuration or data is added; the change
is purely visual on the existing reconciliation widget.
Standard addon install/update (`-u dlv_account_reconciliation_rest_amount`).
No configuration or data is added; the change is a new computed field plus a
purely visual template extension on the existing reconciliation widget.
@@ -0,0 +1 @@
from . import models
@@ -4,11 +4,10 @@
"summary": "Toon het restbedrag tussen haakjes op het afletterscherm "
"(bank reconciliatie)",
"description": """
Voegt het restbedrag (verschil tussen het oorspronkelijke bedrag en het reeds
afgeletterde/toegewezen bedrag) tussen haakjes toe aan het bank-afletterscherm,
zowel bij de regel van het bankafschrift (liquidity-line) als bij de
voorgestelde afletteringsregels (bestaande boekingen) die niet volledig
worden ingezet.
Voegt het restbedrag (verschil tussen het volledige bronbedrag en het bedrag
dat effectief wordt ingezet) tussen haakjes toe op het bank-afletterscherm
(bank.rec.widget), naast een gedeeltelijk gematchte afletteringsregel
(bv. een factuur waarvan niet het volledige bedrag wordt gebruikt).
""",
"author": "bv Domus La Vila",
"website": "https://domuslavila.eu",
@@ -19,7 +18,6 @@ worden ingezet.
"data": [],
"assets": {
"web.assets_backend": [
"dlv_account_reconciliation_rest_amount/static/src/js/*.js",
"dlv_account_reconciliation_rest_amount/static/src/xml/*.xml",
],
},
@@ -0,0 +1 @@
from . import bank_rec_widget_line
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
class BankRecWidgetLine(models.Model):
_inherit = "bank.rec.widget.line"
# Restbedrag = het verschil tussen het volledige (bron)bedrag van de
# boeking en het bedrag dat effectief wordt ingezet om af te letteren.
# Enkel relevant wanneer de boeking niet volledig wordt gebruikt
# (zie display_stroked_balance / flag == 'new_aml').
#
# Elk veld op dit model wordt automatisch geserialiseerd naar de
# 'lines_widget' data (zie bank_rec_widget._compute_lines_widget), dus
# deze twee velden komen vanzelf beschikbaar in de front-end als
# line.rest_debit / line.rest_credit (met .display, .value, .is_zero).
rest_debit = fields.Monetary(
currency_field="company_currency_id",
compute="_compute_dlv_rest_amount",
)
rest_credit = fields.Monetary(
currency_field="company_currency_id",
compute="_compute_dlv_rest_amount",
)
@api.depends("balance", "source_balance")
def _compute_dlv_rest_amount(self):
for line in self:
rest = line.source_balance - line.balance
line.rest_debit = rest if rest > 0.0 else 0.0
line.rest_credit = -rest if rest < 0.0 else 0.0
@@ -1,55 +1,18 @@
odoo.define('dlv_account_reconciliation_rest_amount.reconciliation_renderer', function (require) {
"use strict";
/**
* Toont het restbedrag (het verschil tussen het volledige bedrag van een
* regel en het bedrag dat effectief wordt ingezet om af te letteren) tussen
* haakjes op het afletterscherm.
* DEPRECATED / unused on this Odoo instance.
*
* Dit geldt zowel voor de bankbeweging zelf (de liquidity-line) als voor een
* toegevoegde boeking (bv. een aankoopfactuur) waarvan niet het volledige
* bedrag wordt gebruikt (line.partial_amount != line.amount).
* This file used to patch the legacy `account.ReconciliationRenderer`
* widget (static/src/js/reconciliation/reconciliation_renderer.js in
* account_accountant), which turned out not to be the widget actually used
* on this server. The real reconciliation screen here is the newer OWL
* `bank.rec.widget` (see views/bank_rec_widget_views.xml and
* static/src/components/bank_reconciliation/ in account_accountant).
*
* The rest-amount feature is now implemented server-side on
* models/bank_rec_widget_line.py (rest_debit / rest_credit fields) and
* rendered via static/src/xml/reconciliation_rest_amount.xml, which
* extends `account_accountant.bank_rec_widget_form_lines_widget`.
*
* Kept as an empty file (rather than deleted) because files in this
* workspace folder cannot be removed once written.
*/
var ReconciliationRenderer = require('account.ReconciliationRenderer');
var field_utils = require('web.field_utils');
ReconciliationRenderer.ManualLineRenderer.include({
/**
* @override
*/
update: function (state) {
this._computeRestAmounts(state);
return this._super.apply(this, arguments);
},
/**
* Berekent, voor elke regel in de afletteringsvoorstellen die slechts
* gedeeltelijk wordt ingezet, het nog resterende (niet-afgeletterde)
* bedrag en formatteert dit als rest_amount_str.
*
* @private
* @param {Object} state
*/
_computeRestAmounts: function (state) {
var format_options = {currency_id: state.st_line.currency_id};
_.each(state.reconciliation_proposition, function (line) {
if (!line) {
return;
}
var hasPartialAmount = line.partial_amount && Math.abs(line.partial_amount) !== Math.abs(line.amount);
if (hasPartialAmount) {
var rest = Math.abs(line.amount) - Math.abs(line.partial_amount);
line.rest_amount = rest;
line.rest_amount_str = field_utils.format.monetary(rest, {}, format_options);
} else {
delete line.rest_amount;
delete line.rest_amount_str;
}
});
},
});
});
@@ -2,23 +2,31 @@
<templates xml:space="preserve">
<!--
Voegt het restbedrag (line.rest_amount_str, berekend in
reconciliation_rest_amount.js) tussen haakjes toe naast het bedrag
van een afletteringsregel. Geldt zowel voor de bankbeweging
(liquidity-line) als voor een toegevoegde boeking waarvan niet het
volledige bedrag wordt ingezet.
Voegt het restbedrag (line.rest_debit / line.rest_credit, berekend in
models/bank_rec_widget_line.py) tussen haakjes toe naast het
doorgestreepte bronbedrag van een afletteringsregel die niet
volledig wordt ingezet (bv. een gedeeltelijk gematchte factuur).
Origineel template: reconciliation.line.mv_line.amount
(enterprise-sys/account_accountant/static/src/xml/account_reconciliation.xml)
Origineel template: account_accountant.bank_rec_widget_form_lines_widget
(enterprise-sys/account_accountant/static/src/components/bank_reconciliation/bank_rec_widget.xml)
Dit is een legacy widget-template (gerenderd via core.qweb.render,
geen OWL), dus we breiden ze uit met de oude t-extend/t-jquery
syntax in plaats van <xpath>.
Dit is een echt OWL-template, dus we breiden het uit via
t-inherit-mode="extension" + <xpath>, zodat de patch automatisch
toegepast wordt zonder de JS-component te moeten aanpassen.
-->
<t t-extend="reconciliation.line.mv_line.amount">
<t t-jquery="span.line_amount:last" t-operation="after">
<span t-if="line.rest_amount_str" class="dlv_rest_amount text-muted" title="Nog te matchen"> (<t t-out="line.rest_amount_str"/>)</span>
</t>
<t t-name="dlv_account_reconciliation_rest_amount.bank_rec_widget_form_lines_widget"
t-inherit="account_accountant.bank_rec_widget_form_lines_widget"
t-inherit-mode="extension"
owl="1">
<xpath expr="(//td[@field='debit'])[2]" position="inside">
<span t-if="!line.rest_debit.is_zero" class="dlv_rest_amount text-muted ms-1" title="Nog te matchen"> (<t t-out="line.rest_debit.display"/>)</span>
</xpath>
<xpath expr="(//td[@field='credit'])[2]" position="inside">
<span t-if="!line.rest_credit.is_zero" class="dlv_rest_amount text-muted ms-1" title="Nog te matchen"> (<t t-out="line.rest_credit.display"/>)</span>
</xpath>
</t>
</templates>