Tuesday, September 15, 2026
1 change · 19.0
Resolved issues and error corrections
Uruguayan e-invoicing documents no longer lose their valid tax authority status when a temporary connection problem occurs with Uruware. This prevents valid invoices from being incorrectly marked as failed, avoids accidental duplicate submissions, and lets automatic checks recover once the connection works again.
Original PR description
### Problem A transport failure against Uruware (`Timeout`, `ConnectionError`, `HTTPError`) is caught in `_ucfe_ws_call()` and appended to `errors` as a plain string. `_update_cfe_state()` then…
### Problem
A transport failure against Uruware (`Timeout`, `ConnectionError`, `HTTPError`) is caught in `_ucfe_ws_call()` and appended to `errors` as a plain string. `_update_cfe_state()` then writes `state = 'error'` for anything in `errors`, without looking at the previous state, so a network problem overwrites a state that DGI had already given.
Reported on a customer database: the invoice showed
> Uruguayan e-invoicing: There was a problem with the connection with Uruware: ConnectionError(ProtocolError('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer')))
and **CFE Status: ERROR**, while the CFE was signed and had its CAE at Uruware. The send (message 310) had succeeded — the invoice had its number and the legal PDF, which are only written on a `received`/`accepted` answer. What failed was a later status query (message 360), from the button or from `_l10n_uy_edi_cron_update_dgi_status`.
Two consequences make it worse:
- **It never recovers.** The cron only searches `l10n_uy_edi_cfe_state = 'received'`, so once degraded the document is never queried again.
- **It can duplicate the CFE.** With `state = 'error'`, `_can_edit()` allows editing and `_l10n_uy_edi_send()` replaces the EDI document, so resetting to draft and sending again issues a second CFE over one that is already valid at DGI.
### Fix
Tell a transport failure apart from an answer about the CFE. `_ucfe_ws_call()` flags the result, and the document carries a new `connection_error` field:
- a state in `IRREVERSIBLE_STATES` (`received`, `accepted`, `rejected`) is kept, and the failed call is reported in the chatter and in the log instead of overwriting the diagnosis of the CFE;
- while we ignore whether the CFE reached DGI, the invoice is not offered to be e-invoiced again (`_compute_l10n_uy_edi_is_needed`), its document is not replaced (`_l10n_uy_edi_send`) nor dropped on a repost (`action_post`), and `_can_edit()` returns False;
- `_l10n_uy_edi_cron_update_dgi_status()` also queries those documents, so they recover on their own, and the first real answer clears the flag — including an answer saying the CFE does not exist, which re-enables a legitimate resend.
The red alert on the invoice tells the user not to send it again and points at "Update DGI Status".
### Test plan
`l10n_uy_edi/tests/test_mock.py`, three cases that fail on 19.0 without this commit:
- `test_41_connection_error_does_not_degrade_dgi_state` — `AssertionError: 'error' != 'received'`, the reported symptom;
- `test_42_connection_error_on_send_blocks_resend` — a cut send does not enable a second CFE;
- `test_43_cron_recovers_after_connection_error` — `AssertionError: 'error' != 'accepted'`, the cron recovers the document.
The whole flow was also run against the Uruware testing environment, cutting the connection by pointing the endpoint to a host that does not resolve: a document waiting for DGI keeps its state, a cut send stays blocked, and the status query recovers the CFE by its UUID.