85 lines
3.6 KiB
Python
85 lines
3.6 KiB
Python
from odoo import api, fields, models
|
|
|
|
|
|
class AccountMove(models.Model):
|
|
_inherit = "account.move"
|
|
|
|
last_payment_date = fields.Date(
|
|
compute="_compute_last_payment_info",
|
|
store=True,
|
|
copy=False,
|
|
help="Date of the most recent payment reconciled with this "
|
|
"invoice, whatever the reconciliation path (explicit payment "
|
|
"or direct bank statement line reconciliation).",
|
|
)
|
|
last_payment_method = fields.Char(
|
|
compute="_compute_last_payment_info",
|
|
store=True,
|
|
copy=False,
|
|
help="Payment method of the most recent payment reconciled with this invoice.",
|
|
)
|
|
|
|
@api.depends(
|
|
"line_ids.matched_debit_ids.debit_move_id.date",
|
|
"line_ids.matched_debit_ids.debit_move_id.move_id.origin_payment_id.payment_method_line_id.name",
|
|
"line_ids.matched_debit_ids.debit_move_id.move_id.statement_line_id",
|
|
"line_ids.matched_credit_ids.credit_move_id.date",
|
|
"line_ids.matched_credit_ids.credit_move_id.move_id.origin_payment_id.payment_method_line_id.name",
|
|
"line_ids.matched_credit_ids.credit_move_id.move_id.statement_line_id",
|
|
)
|
|
def _compute_last_payment_info(self):
|
|
"""Compute the last real payment date and method.
|
|
|
|
Only customer and vendor invoices carry the information; every
|
|
other move type gets both fields cleared. Candidates are the
|
|
reconciliation counterpart lines of the receivable/payable
|
|
lines (exchange difference moves excluded). The most recent
|
|
candidate wins; on equal dates the first candidate found wins.
|
|
"""
|
|
for move in self:
|
|
if move.move_type not in ("in_invoice", "out_invoice"):
|
|
move.last_payment_date = False
|
|
move.last_payment_method = False
|
|
continue
|
|
candidates = move._get_last_payment_candidates()
|
|
if not candidates:
|
|
move.last_payment_date = False
|
|
move.last_payment_method = False
|
|
else:
|
|
latest_date, latest_method = max(
|
|
candidates, key=lambda candidate: candidate[0]
|
|
)
|
|
move.last_payment_date = latest_date
|
|
move.last_payment_method = latest_method
|
|
|
|
def _get_last_payment_candidates(self):
|
|
"""Collect the candidate real payments for this invoice.
|
|
|
|
A candidate is a ``(date, method)`` tuple built from each
|
|
reconciliation counterpart line:
|
|
|
|
- counterpart move with ``origin_payment_id``: explicit
|
|
payment, dated with the payment date, method from the
|
|
payment method line;
|
|
- counterpart move with ``statement_line_id``: direct bank
|
|
statement reconciliation, dated with the counterpart move
|
|
date, method fixed to the bank transfer label;
|
|
- any other manual reconciliation is ignored.
|
|
|
|
:return: list of ``(date, method)`` tuples, possibly empty.
|
|
"""
|
|
self.ensure_one()
|
|
invoice_partials, exchange_diff_moves = self._get_reconciled_invoices_partials()
|
|
candidates = []
|
|
for _partial, _amount, counterpart_line in invoice_partials:
|
|
if counterpart_line.move_id.id in exchange_diff_moves:
|
|
continue
|
|
payment = counterpart_line.move_id.origin_payment_id
|
|
if payment:
|
|
candidates.append((payment.date, payment.payment_method_line_id.name))
|
|
elif counterpart_line.move_id.statement_line_id:
|
|
candidates.append(
|
|
(counterpart_line.move_id.date, self.env._("Bank Transfer"))
|
|
)
|
|
return candidates
|