ETA Document Flow
Complete lifecycle, statuses, actions, and enablement rules for E-Invoices, E-Receipts, and E-Received Invoices.
ETA Document Flow
Egyptian Tax Authority (ETA) documents share one policy: EtaActionPolicy in the shared library. The same rules disable Actions in Blazor (EtaActionGate / EtaActionMenuItem) and reject illegal calls on the API.
This guide documents implemented behavior for:
- E-Invoices — sent invoices (
Direction = Sent,Kind = Invoice) - E-Received Invoices — inbound supplier invoices (
Direction = Received,Kind = Invoice) - E-Receipts — sent receipts (
Kind = Receipt; use return, not cancel)
Parent hub: Target Document Flow.
- Draft / Validated / Queued
- Submitted
- Valid
- Invalid / Rejected
- Cancelled / Returned
#Status catalog
Statuses are stored as strings on the document and mapped to EtaDocumentStatus.
| Status | Invoices | Receipts | Meaning |
|---|---|---|---|
Draft |
Yes | Yes | Editable local draft |
Validated |
Yes | Yes | Passed local/pre-ETA validation |
Queued |
— | Yes | Accepted offline; waiting to submit |
Submitted |
Yes | Yes | Sent; awaiting authority result |
Valid |
Yes | Yes | Accepted by ETA |
Invalid |
Yes | Yes | Refused by ETA; fix and resubmit |
Rejected |
Yes | Yes* | Counterparty refused (invoice-centric) |
Cancelled |
Yes | — | Issuer cancelled at ETA |
Returned |
— | Yes | Fully reversed by return receipt |
* Receipts do not use recipient Reject / Decline Cancellation; reverse with Create Return Or Cancel Receipt.
#Lifecycle overview
Core path — prepare, submit, ETA result
flowchart TB
subgraph Prepare["1 - Prepare"]
direction TB
Draft[Draft]
Validated[Validated]
Queued[Queued - receipts]
Draft -->|Validate| Validated
end
subgraph Authority["2 - Authority"]
Submitted[Submitted]
end
subgraph Result["3 - Result"]
direction TB
Valid[Valid]
Invalid[Invalid]
end
Start((Create)) --> Draft
Draft -->|Submit| Submitted
Validated -->|Submit| Submitted
Queued -->|Submit| Submitted
Submitted -->|ETA accept| Valid
Submitted -->|ETA refuse| Invalid
Draft -.->|Submit refused| Invalid
Validated -.->|Submit refused| Invalid
Invalid -->|Edit| Draft
Invalid -->|Resubmit| Submitted
class Start egkStart
class Draft,Validated,Queued egkDraft
class Submitted egkActive
class Valid egkSuccess
class Invalid egkError
Terminal paths from Valid — cancel, reject, or return
flowchart TB Valid[Valid] Valid -->|Cancel on ETA| Cancelled[Cancelled] Valid -->|Reject invoice| Rejected[Rejected] Valid -->|Create return| Returned[Returned] Cancelled --> DoneNode((Done)) Rejected --> DoneNode Returned --> DoneNode class Valid egkSuccess class Cancelled,Rejected,Returned egkTerminal class DoneNode egkStart
#Direction split (invoices)
ETA gives each side one reversal verb. Receipts use Create Return Or Cancel Receipt, not Cancel On Eta.
Issuer vs recipient reversal actions
flowchart TB
subgraph Issuer["Issuer - E-Invoices"]
direction TB
S1[Valid] -->|Cancel on ETA| S2[Cancelled]
S1 -->|Decline rejection| S3[Reinstate / clear pending]
end
subgraph Recipient["Recipient - E-Received Invoices"]
direction TB
R1[Valid] -->|Reject invoice| R2[Rejected]
R1 -->|Decline cancellation| R3[Reinstate / clear pending]
end
class S1,R1 egkSuccess
class S2,R2 egkTerminal
class S3,R3 egkActive
| Verb (UI label) | Who | Policy action |
|---|---|---|
| Cancel On Eta | Issuer | Cancel |
| Decline Rejection | Issuer | DeclineRejection |
| Reject Invoice | Recipient | Reject |
| Decline Cancellation | Recipient | DeclineCancellation |
| Create Return Or Cancel Receipt | Receipt issuer | IssueReturn |
| Create Credit Note | Invoice issuer | IssueCreditNote |
#Action availability matrix
Legend: Y = allowed when other flags permit · — = never for this kind/direction · C = conditional (see notes)
Sent e-invoice matrix
| Action (UI) | Draft | Validated | Submitted | Valid | Invalid | Rejected | Cancelled |
|---|---|---|---|---|---|---|---|
| Edit / Delete / Line Items | Y | Y | — | — | Y | — | — |
| Validate | Y | Y | — | — | Y | — | — |
| Submit | Y | Y | — | — | Y | — | — |
| Sync Status | C¹ | C¹ | C¹ | C¹ | C¹ | C¹ | C¹ |
| Cancel On Eta | — | — | — | C² | — | — | — |
| Decline Rejection | — | — | — | C³ | — | C³ | C³ |
| Create Credit Note | — | — | — | C⁴ | — | — | — |
| Duplicate | Y | Y | Y | Y | Y | Y | Y |
| Eta Pdf | C¹ | C¹ | C¹ | C¹ | C¹ | C¹ | C¹ |
¹ Requires ETA document UUID (HasEtaUuid).
² Valid only; blocked if pending cancellation, pending rejection, or reversal window closed.
³ Requires pending rejection or status Rejected/Cancelled per decline rules; blocked if already declined, no rejection, wrong direction, or decline window closed while still Valid.
⁴ Valid only and not fully credited; no cancellation deadline (credit note remains available after the cancel window).
Received e-invoice & e-receipt matrices
#Received e-invoice
| Action (UI) | Valid | Other statuses |
|---|---|---|
| Reject Invoice | C⁵ | Denied (not submitted / wrong status / already reversed) |
| Decline Cancellation | C⁶ | See decline rules |
| Sync / Eta Pdf | C¹ | C¹ |
| Submit / Cancel / Credit Note | — | Sender-only or N/A |
⁵ Valid only; within rejection window; no pending rejection.
⁶ Pending cancellation or status Cancelled; receiver only; one decline; window rules as in policy.
#E-receipt
| Action (UI) | Draft / Validated / Queued / Invalid | Submitted | Valid | Returned |
|---|---|---|---|---|
| Edit / Delete | Y | — | — | — |
| Validate / Submit | Y | — | — | — |
| Create Return Or Cancel Receipt | — | — | C⁷ | — |
| Cancel On Eta | — | — | — | — (receipts use return) |
| Duplicate | Y | Y | Y | Y |
⁷ Valid and not fully returned.
#Decision trees
#When is Cancel On Eta enabled?
Cancel On Eta — policy gates
flowchart TB
A[Cancel On Eta] --> B{Kind = Invoice?}
B -->|No| X1[Denied - use return]
B -->|Yes| C{Direction = Sent?}
C -->|No| X2[Denied - sender only]
C -->|Yes| D{Pending cancellation?}
D -->|Yes| X3[Denied - already requested]
D -->|No| E{Pending rejection?}
E -->|Yes| X4[Denied - rejection pending]
E -->|No| F{Status = Valid?}
F -->|No| X5[Denied - not Valid]
F -->|Yes| G{Reversal window closed?}
G -->|Yes| X6[Denied - window closed]
G -->|No| OK[Allowed]
class A egkActive
class B,C,D,E,F,G egkDecision
class OK egkSuccess
class X1,X2,X3,X4,X5,X6 egkError
#When is Decline Rejection enabled?
Decline Rejection — policy gates
flowchart TB
A[Decline Rejection] --> B{Invoice + Sent?}
B -->|No| X1[Denied - wrong kind]
B -->|Yes| C{Has ETA UUID?}
C -->|No| X2[Denied - not submitted]
C -->|Yes| D{Already declined?}
D -->|Yes| X3[Denied - already declined]
D -->|No| E{Pending rejection or Rejected?}
E -->|No| X4[Denied - no rejection]
E -->|Yes| F{Status}
F -->|Valid| G{Decline window closed?}
G -->|Yes| X5[Denied - window closed]
G -->|No| OK[Allowed]
F -->|Rejected or Cancelled| OK
F -->|Other| X4
class A egkActive
class B,C,D,E,F,G egkDecision
class OK egkSuccess
class X1,X2,X3,X4,X5 egkError
#After-action UI behavior (ETA screens)
| Step | Behavior |
|---|---|
| 1 | Action runs through API (/{id}/validate, /submit, /cancel, /decline-rejection, /reject, /decline-cancellation, /return, /sync-status, …) |
| 2 | ETA actions stay disabled for the round trip and the refresh that follows, so nothing can be launched against a row already known to be out of date |
| 3 | The row and the status counters above it are re-read from the server on every outcome — accepted, refused, or failed |
| 4 | If composer/details open: refetch invoice/receipt/received invoice by id |
| 5 | Gate(row, action) / DeclineRejectionGate / DeclineCancellationGate re-run on the new StatusId, UUID, and ETA date flags |
| 6 | A multi-row selection is re-pointed at the reloaded rows, so bulk buttons gate on the new statuses; rows the reload no longer returns drop out of the selection |
| 7 | Disabled items remain visible with localized denial tooltips |
A refused action refreshes the same as an accepted one. A refusal usually means the document had already moved on — cancelled by someone else, or past its window — which is exactly the case where the row on screen is the stale thing that offered the action. A refused submission also still writes to the document: the reason ETA gave, and the attempt in the audit trail. So the screen after a refusal shows the authority's current answer rather than the state you clicked from, and no manual refresh is needed to find out what is still possible.
Validate is included in this, despite the read-only name: a draft that passes validation is promoted to Validated and saved, which changes what the Actions menu should offer.
EntityTable CanUpdateEntityFunc / CanDeleteEntityFunc also call EtaActionPolicy so built-in Edit/Delete match the Actions menu.
#Scenario catalog
| Scenario | Resulting status / flags | User next step |
|---|---|---|
| Create | Draft |
Edit lines, Validate, Submit |
| Validate success | Often Validated |
Submit |
| Submit success | Submitted then sync to Valid / Invalid |
Sync Status if needed |
| ETA invalid | Invalid |
Edit, Validate, Submit |
| Cancel accepted | Pending cancel → Cancelled |
Decline not available to issuer |
| Reject accepted | Pending reject → Rejected |
Issuer may Decline Rejection inside window |
| Decline Rejection success | Pending cleared; document reinstated | Continue as Valid |
| Decline Cancellation success | Pending cleared; document reinstated | Recipient keeps invoice |
| Full credit note | Source stays Valid; FullyCredited |
Credit note action disabled |
| Full return | Source → Returned or FullyReturned |
Return action disabled |
| Duplicate | New Draft |
Unrelated to source lock |
#Sequence: submit sent invoice
Submit path — gate → API → ETA → UI sync
sequenceDiagram
autonumber
participant UI as Invoices grid
participant Gate as EtaActionGate
participant API as Invoice API
participant Svc as Submission service
participant ETA as Tax authority
participant DB as Database
UI->>Gate: Evaluate Submit
Gate-->>UI: Allow or deny + tooltip
UI->>API: POST /{id}/submit
API->>Svc: SubmitInvoiceToEta
Svc->>DB: Read invoice
Svc->>ETA: Submit document
ETA-->>Svc: UUID / validation result
Svc->>DB: Persist StatusId + UUID
API-->>UI: Outcome
UI->>UI: Reload grid + re-gate Actions
#Denial reasons (tooltips)
Denial keys resolve through the module localizer. Examples:
- Action Denied Locked By Eta
- Action Denied Already Submitted
- Action Denied Only Valid Can Be Cancelled
- Action Denied Cancellation Already Requested
- Action Denied Decline Window Closed
- Action Denied Decline Rejection Is Sender Only
- Action Denied Decline Cancellation Is Receiver Only
- Action Denied Receipts Use Return