Časté validační chyby Peppol BIS 3.0 a jak je opravit
Validační selhání Peppol BIS 3.0 spadají do předvídatelné sady kategorií. Chybové zprávy odkazují na kódy obchodních pravidel (BR-xx) a čísla obchodních termínů (BT-xx) ze standardu EN16931, jejichž pochopení vyžaduje přečtení specifikace. Tento článek mapuje nejčastější selhání na jejich příčiny a poskytuje konkrétní opravy.
Všechny příklady používají syntaxi UBL 2.1. Pro ekvivalenty CII viz UBL vs CII.
BR-01 až BR-06: chybějící povinná pole záhlaví
Tato pravidla vynucují přítomnost povinných polí nejvyšší úrovně. Selžou, pokud element chybí nebo je prázdný.
| Pravidlo | Pole | BT | Oprava |
|---|---|---|---|
| BR-01 | Identifikátor specifikace | BT-24 | Přidejte CustomizationID s přesným URI Peppol BIS 3.0 |
| BR-02 | Číslo faktury | BT-1 | Přidejte neprázdný element ID |
| BR-03 | Datum vystavení faktury | BT-2 | Přidejte IssueDate ve formátu YYYY-MM-DD |
| BR-04 | Kód měny faktury | BT-5 | Přidejte DocumentCurrencyCode s kódem ISO 4217 |
| BR-05 | Název prodávajícího | BT-27 | Přidejte AccountingSupplierParty/Party/PartyName/Name |
| BR-06 | Název kupujícího | BT-44 | Přidejte AccountingCustomerParty/Party/PartyName/Name |
Specificky k BR-01: nejčastější příčinou je použití základního URI EN16931 namísto URI Peppol BIS 3.0. Vypadají podobně, ale jsou různé:
Špatně (základní EN16931):
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
Správně (Peppol BIS 3.0):
<cbc:CustomizationID>
urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1
</cbc:CustomizationID>
Validátor kontroluje přesný řetězec. Kontext toho, proč na tom záleží, viz Úvod do Peppol BIS 3.0.
BR-CO-10: součet částek řádků neodpovídá celkové hodnotě
[BR-CO-10]-Sum of Invoice line net amount (BT-106) =
sum of Invoice line net amount (BT-131).
Toto pravidlo vyžaduje, aby LegalMonetaryTotal/LineExtensionAmount (BT-106) rovnalo součtu všech hodnot InvoiceLine/LineExtensionAmount (BT-131).
Selhání je téměř vždy způsobeno chybou zaokrouhlování. Pokud zaokrouhlíte každou částku řádku nezávisle před součtem, součet zaokrouhlených hodnot se může lišit od zaokrouhleného součtu surových hodnot.
Špatně (zaokrouhlování po řádcích, pak sčítání):
// Line 1: 3 × 33.333... = 100.00 (rounded)
// Line 2: 3 × 33.333... = 100.00 (rounded)
// Sum of rounded: 200.00
// But raw sum: 3 × 33.333... + 3 × 33.333... = 200.00 exactly in this case
Selhání je zřetelnější u sazeb jako 7% DPH na různá množství, kde se zaokrouhlování hromadí přes mnoho řádků.
Správný přístup: sečtěte surové nezaokrouhlené hodnoty přes všechny řádky, pak zaokrouhlete agregát jednou:
var lineNetTotal = invoiceLines.Sum(l => l.Quantity * l.UnitPrice); // raw
var lineNetTotalRounded = Math.Round(lineNetTotal, 2, MidpointRounding.AwayFromZero);
BR-CO-15: selhání aritmetiky celkové výše DPH faktury
[BR-CO-15]-Invoice total VAT amount (BT-110) =
sum of VAT category tax amount (BT-117).
Celková výše DPH v TaxTotal/TaxAmount musí být rovna součtu hodnot TaxTotal/TaxSubtotal/TaxAmount přes všechny daňové kategorie.
U jednosazbové faktury to vypadá triviálně, ale selhání nastávají, když:
- Existuje více sazeb DPH a zaokrouhlování se aplikuje po kategoriích, nikoli na agregát
- Je přítomna kategorie nulové sazby nebo osvobození a její
TaxAmountje0.00, nikoli chybějící TaxAmountna úrovniTaxTotalse počítá nezávisle od částekTaxSubtotal
Oprava: nejprve vypočítejte všechny hodnoty TaxSubtotal/TaxAmount, sečtěte je a použijte tento součet jako hodnotu TaxTotal/TaxAmount. Nepočítejte TaxTotal/TaxAmount samostatně.
BR-CO-16: splatná částka
[BR-CO-16]-Amount due for payment (BT-115) =
Invoice total with VAT (BT-112) - Paid amount (BT-113) + Rounding amount (BT-114).
Pokud BT-113 (zaplacená částka) a BT-114 (částka zaokrouhlení) nejsou přítomny, zjednodušuje se to na BT-115 = BT-112. Selhání nastává, když PayableAmount a TaxInclusiveAmount se liší o více než povolenou toleranci zaokrouhlování.
Častá příčina: výpočet PayableAmount ze zaokrouhlených částek řádků a TaxInclusiveAmount z oddělené kalkulace celkové hodnoty, která produkuje mírně odlišný výsledek.
Oprava: vypočítejte jednu kanonickou celkovou hodnotu, použijte ji pro TaxInclusiveAmount i PayableAmount.
BR-S-08 a BR-S-09: konzistence sazby a výše DPH
[BR-S-08]-For each different value of VAT category rate (BT-119) where the
VAT category code (BT-118) is "S", the VAT category taxable amount (BT-116)
in a VAT breakdown (BG-23) shall equal the sum of Invoice line net amounts
(BT-131) where the VAT category code of the Invoice line (BT-151) is "S"
and the VAT rate for the Invoice line (BT-152) equals the VAT category rate.
Toto pravidlo seskupuje všechny řádky podle sazby DPH a ověřuje, že zdanitelná částka v každém TaxSubtotal odpovídá součtu řádků s danou sazbou. Selže, když:
- Řádek má sazbu DPH, pro kterou neexistuje odpovídající
TaxSubtotal - Existuje
TaxSubtotalpro sazbu, ale žádné řádky danou sazbu nepoužívají - Rozdíly v zaokrouhlování se hromadí mezi výpočty na úrovni řádků a mezisoučtů
Oprava: sestavujte elementy TaxSubtotal dynamicky z položek řádků, seskupených podle (kód kategorie DPH, sazba DPH), nikoli je konstruujte nezávisle.
BR-E-01 / BR-AE-01: reverse charge a faktury osvobozené od daně
[BR-E-01]-An Invoice that contains an Invoice line (BG-25), a Document level
allowance (BG-20) or a Document level charge (BG-21) where the VAT category
code (BT-151) is "E" shall contain exactly one VAT breakdown...
Faktury s osvobozenou (E), přenesenou daňovou povinností (AE) nebo nulovou sazbou (Z) DPH vyžadují specifické struktury TaxCategory, které se liší od faktur se standardní (S) sazbou.
Časté chyby:
- Použití hodnoty
IDSpro všechny řádky bez ohledu na skutečné daňové zacházení - Vynechání elementů
TaxExemptionReasonCodeneboTaxExemptionReasonpožadovaných pro osvobozené kategorie - Chybějící
AccountingSupplierParty/Party/PartyTaxScheme, když faktura používá přenesenou daňovou povinnost
Pro přenesenou daňovou povinnost (AE) musí být přítomen daňový identifikátor kupujícího a rovněž daňový identifikátor prodávajícího.
Pravidla rozšíření specifická pro Peppol: Německo
Německé profily Peppol přidávají pravidla nad rámec základu EN16931. Časté chyby:
BR-DE-TMP-32: datum doručení (BT-72) je povinné pro německé B2G faktury. Přidejte Delivery/ActualDeliveryDate ve formátu YYYY-MM-DD.
BR-DE-18: musí být přítomen buď daňový identifikátor prodávajícího (BT-31) nebo daňové registrační číslo (BT-32). Chybí-li oboje, dochází k odmítnutí. Pokud je prodávající osvobozen od DPH, uveďte BT-32 s daňovým registračním číslem.
BR-DE-16: reference kupujícího (BT-10, Leitweg-ID) je povinná pro německé B2G faktury. Formát Leitweg-ID je validován: musí odpovídat vzoru \d{2,12}-\d{4,12}-\d{2}.
Efektivní ladění
Výstup Schematron chyb obsahuje umístění XPath:
<svrl:failed-assert location="/Invoice[1]/cac:LegalMonetaryTotal[1]">
<svrl:text>[BR-CO-10]-Sum of Invoice line net amounts...</svrl:text>
</svrl:failed-assert>
Použijte umístění XPath pro přímou navigaci k selhávajícímu elementu. U aritmetických pravidel přidejte ladící výstup, který zaznamenává surové hodnoty před zaokrouhlením, abyste mohli sledovat, kde nesrovnalost vzniká.
Předkompilované soubory XSLT z vydání Peppol BIS na GitHubu jsou autoritativními validačními artefakty. Spouštějte je se Saxon HE, jak je popsáno v článku generování faktur Peppol BIS 3.0 v C#. Spuštění vůči nejnovějšímu vydání je důležité: sady pravidel se aktualizují s každým vydáním Peppol BIS a pravidlo, které projde starším XSLT, může selhat vůči aktuálnímu.
SealDoc a validační chyby
SealDoc spouští Schematron validaci EN16931 a Peppol BIS 3.0 na každé faktuře před doručením. Pokud validace selže, API vrátí strukturovanou chybovou odpověď mapující každé selhání na jeho kód BR, porušený BT a umístění XPath v odeslaném dokumentu.
Pro organizace ladící existující pipeline generování faktur veřejný validátor SealDoc přijímá soubory faktur UBL a CII, spouští aktuální XSLT Peppol BIS 3.0 a vrací úplný seznam selhání s popisem v přirozeném jazyce. Sady pravidel jsou udržovány aktuální s vydáními Peppol BIS, takže validátor vždy odráží pravidla, která použije přijímající přístupový bod.