payment_residual_display/models/account_payment.py
2025-12-03 15:39:08 +07:00

73 lines
2.8 KiB
Python

from odoo import api, fields, models, _
class AccountPayment(models.Model):
_inherit = 'account.payment'
# Computed residual amount field
payment_residual = fields.Monetary(
string='Payment Residual',
compute='_compute_payment_residual',
currency_field='currency_id',
help="Residual amount of this payment (amount not yet reconciled)",
readonly=True
)
payment_residual_currency = fields.Monetary(
string='Payment Residual Currency',
compute='_compute_payment_residual',
currency_field='currency_id',
help="Residual amount in payment currency",
readonly=True
)
@api.depends('move_id.line_ids.amount_residual',
'move_id.line_ids.amount_residual_currency',
'move_id.line_ids.account_id',
'move_id.line_ids.account_id.account_type',
'is_matched')
def _compute_payment_residual(self):
"""Compute the residual amount for payments.
Matched payments always display zero residual.
For unmatched payments, we first look at residuals on reconcilable counterpart
lines (receivable/payable/write-off). If those are fully cleared, we fall back
to the liquidity lines to surface outstanding balances waiting for bank
statement matching.
"""
for pay in self:
if pay.is_matched or not pay.move_id:
pay.payment_residual = 0.0
pay.payment_residual_currency = 0.0
continue
company_currency = pay.company_id.currency_id
payment_currency = pay.currency_id or company_currency
liquidity_lines, counterpart_lines, writeoff_lines = pay._seek_for_lines()
reconcilable_lines = (counterpart_lines + writeoff_lines).filtered(lambda l: l.account_id.reconcile)
residual = sum(reconcilable_lines.mapped('amount_residual'))
residual_currency = sum(
reconcilable_lines.mapped(
'amount_residual_currency' if payment_currency != company_currency else 'amount_residual'
)
)
liquidity_residual = sum(liquidity_lines.mapped('amount_residual'))
liquidity_residual_currency = sum(
liquidity_lines.mapped(
'amount_residual_currency' if payment_currency != company_currency else 'amount_residual'
)
)
if not company_currency.is_zero(liquidity_residual):
residual = liquidity_residual
if not payment_currency.is_zero(liquidity_residual_currency):
residual_currency = liquidity_residual_currency
pay.payment_residual = abs(residual)
pay.payment_residual_currency = abs(residual_currency)