{"record":{"id":"cac16a7861105c9e","repo":"odoo/odoo","slug":"you-can-t-edit-the-following-journal-entry-s-beca","errorCode":null,"errorMessage":"You can't edit the following journal entry %s because an electronic document has already been sent. Please use the 'Request EDI Cancellation' button instead.","messagePattern":"You can't edit the following journal entry (.+?) because an electronic document has already been sent\\. Please use the 'Request EDI Cancellation' button instead\\.","errorType":"exception","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"addons/account_edi/models/account_move.py","lineNumber":295,"sourceCode":"        # Set the electronic document to be canceled and cancel immediately for synchronous formats.\n        res = super().button_cancel()\n\n        self.edi_document_ids.filtered(lambda doc: doc.state != 'sent').write({'state': 'cancelled', 'error': False, 'blocking_level': False})\n        self.edi_document_ids.filtered(lambda doc: doc.state == 'sent').write({'state': 'to_cancel', 'error': False, 'blocking_level': False})\n        self.edi_document_ids._process_documents_no_web_services()\n        self.env.ref('account_edi.ir_cron_edi_network')._trigger()\n\n        return res\n\n    def _edi_allow_button_draft(self):\n        self.ensure_one()\n        return not self.edi_show_cancel_button\n\n    def button_draft(self):\n        # OVERRIDE\n        for move in self:\n            if not move._edi_allow_button_draft():\n                raise UserError(_(\n                    \"You can't edit the following journal entry %s because an electronic document has already been \"\n                    \"sent. Please use the 'Request EDI Cancellation' button instead.\",\n                    move.display_name))\n\n        res = super().button_draft()\n\n        self.edi_document_ids.write({'error': False, 'blocking_level': False})\n        self.edi_document_ids.filtered(lambda doc: doc.state == 'to_send').unlink()\n\n        return res\n\n    def button_cancel_posted_moves(self):\n        '''Mark the edi.document related to this move to be canceled.\n        '''\n        to_cancel_documents = self.env['account.edi.document']\n        for move in self:\n            move._check_fiscal_lock_dates()\n            is_move_marked = False","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/account_edi/models/account_move.py#L277-L313","documentation":"Raised by account_edi's override of account.move.button_draft(). For each move, if _edi_allow_button_draft() is False — which happens when edi_show_cancel_button is True, i.e. an EDI document has already been sent through a webservice — resetting to draft is refused. The already-transmitted electronic document cannot be silently altered; you must request an EDI cancellation instead.","triggerScenarios":"Calling button_draft() (the 'Reset to Draft' action) on a posted invoice whose EDI document has state 'sent' for a webservice format and which therefore exposes edi_show_cancel_button (Request EDI Cancellation).","commonSituations":"User wants to correct an invoice that was already submitted to a government/e-invoicing network (Peppol, national portals); automation scripts that bulk reset posted invoices to draft and hit sent EDI documents; double-entry workflows unaware of EDI states.","solutions":["Use the 'Request EDI Cancellation' button on the invoice: it asks the webservice to cancel the transmitted document and, once accepted, lets you reset/edit the move.","If the service already rejected/failed cancellation, follow the format's cancellation workflow (some services require issuing a credit note instead).","For non-webservice EDI formats (or docs never sent), _edi_allow_button_draft() returns True — verify edi_document_ids states if you believe no document was actually sent.","In scripts, skip moves where not move._edi_allow_button_draft() and route them to the cancellation flow instead of button_draft()."],"exampleFix":"# before\nfor move in moves:\n    move.button_draft()  # raises for sent EDI documents\n\n# after\nfor move in moves:\n    if move._edi_allow_button_draft():\n        move.button_draft()\n    else:\n        # route to the EDI cancellation workflow instead\n        move.message_log(body='EDI cancellation required before resetting to draft')","handlingStrategy":"validation","validationCode":"blocked = moves.filtered(lambda m: not m._edi_allow_button_draft())\nif blocked:\n    route_to_edi_cancellation(blocked)  # do not call button_draft on these","typeGuard":"def can_reset_to_draft(move) -> bool:\n    return not move.edi_show_cancel_button","tryCatchPattern":"from odoo.exceptions import UserError\nfor move in moves:\n    try:\n        move.button_draft()\n    except UserError as e:\n        if 'Request EDI Cancellation' in str(e):\n            continue  # handle via cancellation flow\n        raise","preventionTips":["Always gate button_draft() with _edi_allow_button_draft() in batch scripts","Train users: sent e-invoices are corrected via EDI cancellation, never reset-to-draft"],"tags":["odoo","edi","accounting","workflow","state-machine"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}