Error codes / 1343
EFRIS error 1343 — summary.netAmount does not equal gross minus tax
URA recomputed your summary block and found that
summary.netAmount is not summary.grossAmount − summary.taxAmount. Derive
netAmount by subtraction, from the converted taxDetails you are
actually transmitting — not from a net your own system computed and rounded earlier.
netAmount = grossAmount - taxAmount
Both operands come from the transmitted taxDetails. Never copy netAmount from a
caller, an order model, or a per-line sum.
What URA returns
The rejection arrives in the response envelope with the code in returnStateInfo.returnCode:
{
"returnStateInfo": {
"returnCode": "1343",
"returnMessage": "..."
}
}
URA rewords returnMessage between releases and some messages come back in mixed language, so
branch on returnCode and never on the message text:
from efris import EfrisError
try:
client.upload_invoice(document)
except EfrisError as exc:
if exc.code == "1343":
... # rebuild summary from taxDetails, then resubmit
raise
Log the whole decrypted payload when a document fails. URA frequently puts the useful detail in a nested
field rather than in returnMessage, and a batch can be partly accepted — the envelope says
"00" while individual lines were rejected, surfaced as
EfrisValidationError.failures.
What it actually means
The summary block is not header data URA stores on trust. URA recomputes it from the arrays
you sent and rejects any disagreement. 1343 is the identity check on that recomputation.
Almost every occurrence has the same shape: grossAmount and taxAmount were
derived from taxDetails, but netAmount came from somewhere else — an ERP order
total, a per-line net summed at a different precision, or a value the API caller supplied. The two paths
agree to within a fraction of a shilling, and URA allows no tolerance. Note that the check applies to the
converted taxDetails: if your pipeline normalises tax rates, maps snake_case keys to
camelCase, or reformats amounts to two decimal places, the numbers URA validates are the numbers produced
after that step, not the ones you computed before it.
The fix
Build all three summary amounts in one function, from the taxDetails list that is about to be
serialised into the request body. Call it last, after every conversion, immediately before signing.
def summary_amounts(tax_details):
"""The three summary amounts, derived from the transmitted taxDetails.
taxAmount - sum of every group, INCLUDING excise (category "05").
grossAmount- sum of every group EXCEPT excise; excise is already embedded
in the standard-rate group's gross.
netAmount - derived, never supplied.
"""
tax_amount = sum(float(td["taxAmount"]) for td in tax_details)
gross_amount = sum(
float(td["grossAmount"])
for td in tax_details
if str(td.get("taxCategoryCode", "")) != "05"
)
net_amount = gross_amount - tax_amount
return {
"netAmount": f"{net_amount:.2f}",
"taxAmount": f"{tax_amount:.2f}",
"grossAmount": f"{gross_amount:.2f}",
}
document["summary"].update(summary_amounts(document["taxDetails"]))
Amounts are transmitted as JSON strings, so format them to a fixed two decimal places rather than letting
a float render as 59000.000000001.
On an invoice carrying excise duty, summary.netAmount is not the sum of the
taxDetails net amounts. It is derived from a gross that excludes tax category
05 and a tax that includes it. Summing the per-group nets gives a different, wrong figure. See
1344 and 1345.
Why this happens
EFRIS treats taxDetails as the authoritative statement of the document and summary
as a checksum over it. Anything URA can recompute, URA does recompute: the amounts here, and the line count in
1304. The purpose is that a fiscal document cannot claim one tax position in
its detail and another in its header.
That framing gives the general rule for the whole summary block. There should be exactly one place in your
code that produces summary, it should take the final goodsDetails and
taxDetails as its only inputs, and it should run after every transformation those arrays undergo.
A summary assembled earlier in the pipeline — or partly supplied by the caller — will eventually disagree with
what is transmitted, and the failure appears as 1343, 1344, 1345 or 1304 depending on which field drifted.
Related errors
- 1344 taxAmount mismatch —
summary.taxAmountmust include excise duty, tax category05. - 1345 grossAmount mismatch —
summary.grossAmountmust exclude tax category05. The mirror of 1344. - 1304 itemCount mismatch — count product lines only; exclude entries with
discountFlag "0".
The full list, with the fix for each, is at /docs/errors/.
If you would rather not maintain this
The EFRIS API Kit builds the summary from the converted taxDetails at
submission time, on invoices and credit notes alike, so the identity above always holds. The rule is correct
whether or not you use it.