odoo/odoo · error · UserError
You can't block a paid invoice.
Error message
You can't block a paid invoice.
What it means
Raised by account.move.action_toggle_block_payment() when a user tries to set the 'blocked' payment state on an invoice whose payment_state is already 'paid' or 'in_payment'. Blocking payments only makes sense for open invoices; once payments are (being) registered, the toggle refuses to mark it blocked.
Source
Thrown at addons/account/models/account_move.py:6372
moves_to_reset_draft = self.filtered(lambda x: x.state == 'posted')
if moves_to_reset_draft:
moves_to_reset_draft.button_draft()
if any(move.state != 'draft' for move in self):
raise UserError(_("Only draft journal entries can be cancelled."))
self.line_ids.remove_move_reconcile()
self.payment_ids.state = "canceled"
self.write({'auto_post': 'no', 'state': 'cancel'})
def action_toggle_block_payment(self):
self.ensure_one()
if self.payment_state == 'blocked':
self.payment_state = 'not_paid'
self.env.add_to_compute(self._fields['payment_state'], self)
else:
if self.payment_state in ('paid', 'in_payment'):
raise UserError(_("You can't block a paid invoice."))
self.payment_state = 'blocked'
def action_activate_currency(self):
self.currency_id.filtered(lambda currency: not currency.active).write({'active': True})
def action_delete_duplicates(self):
for move in self:
move.duplicated_ref_ids.unlink()
def _get_mail_template(self):
"""
:return: the correct mail template based on the current move type
"""
template_xmlid = 'account.email_template_edi_invoice'
if all(move.move_type == 'out_refund' for move in self):
template_xmlid = 'account.email_template_edi_credit_note'
elif all(move.move_type == 'in_invoice' and move.journal_id.is_self_billing for move in self):
template_xmlid = 'account.email_template_edi_self_billing_invoice'View on GitHub (pinned to 1e661df964)
Solutions
- Refresh the record and re-check payment_state before toggling; only block when state is 'not_paid', 'partial' or similar open state.
- If the intent is to undo a payment, unreconcile/cancel the payment (payment_ids) instead of blocking the invoice.
- In custom wizards, guard: if move.payment_state in ('paid', 'in_payment'): skip or inform the user.
Example fix
# before
invoice.action_toggle_block_payment()
# after
if invoice.payment_state not in ('paid', 'in_payment'):
invoice.action_toggle_block_payment() Defensive patterns
Strategy: validation
Validate before calling
if invoice.payment_state in ('paid', 'in_payment'):
raise UserError(_("Invoice %s is already paid; cannot block.", invoice.name))
invoice.action_toggle_block_payment() Try / catch
from odoo.exceptions import UserError
try:
invoice.action_toggle_block_payment()
except UserError as e:
if "can't block a paid invoice" in str(e):
invoice.invalidate_recordset() # stale UI data; refresh and inform user
raise
raise Prevention
- Hide the block-payment toggle when payment_state is 'paid'/'in_payment'.
- Refresh the form before toggling; payments may have registered since page load.
- To undo a payment, unreconcile the payment instead of blocking.
When it happens
Trigger: Clicking the 'Block Payment' toggle (or calling action_toggle_block_payment() over RPC) on an invoice with payment_state in ('paid', 'in_payment'). This state is reached when the invoice is fully reconciled with payments or a payment is in transit (in_payment via bank SUSPENSE).
Common situations: UI race: the invoice gets paid between page load and the user clicking the toggle; automated scripts flipping payment_state on old records; user trying to 'undo' a payment by blocking instead of unreconciling the payment.
Related errors
- Only draft journal entries can be cancelled.
- You can only request a cancellation for invoice sent to the
- The account %(name)s (%(code)s) is archived.
- The account selected on your journal entry forces to provide
- The operation is refused as it would impact an already issue
AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15).
Data as JSON: /api/errors/c2ff87d463d59c29.
Report an issue: GitHub.