E-Rechnung in Panama aus SAP Business One: NUC-JSON-Feldzuordnung und DGI-Ablehnungen
Von Zain Abbas, Kodenova · Aktualisiert am
Um eine elektronische Rechnung in Panama (Factura Electrónica, FE) aus SAP Business One über den PAC Digifact auszustellen, senden Sie pro Rechnung oder Gutschrift ein NUC-JSON-Dokument. Die meisten Daten liegen bereits in OINV, INV1, OCRD und OITM. Was SAP B1 standardmäßig nicht hat, sind Empfängertyp, Prüfziffer des RUC (DV), Ortscode (CodUbi) und der CPBS-Artikelcode; diese werden zu benutzerdefinierten Feldern. Der PAC antwortet mit einem CUFE, einem Autorisierungsprotokoll und einer QR-URL, die Sie in den Beleg zurückschreiben.
Dieser Leitfaden beschreibt die Zuordnung, die ich in meinem SAP-Business-One-Add-on für Panama verwende. Getestet wurde sie am 27. Oktober 2026 in einem SAP-B1-10-Mandanten auf SQL Server gegen die Sandbox von Digifact: 34 Szenarien, von einer Endkundenrechnung mit 7 % bis zu einer Rechnung mit 105 Positionen, Exporte, zona franca, Gutschriften und Stornierungen. Den kaufmännischen Überblick finden Sie unter E-Rechnung in Panama für SAP Business One.
Wie läuft der Weg von SAP Business One zur DGI?
- Der Benutzer legt in SAP B1 wie gewohnt eine Ausgangsrechnung (Objekt 13) oder Ausgangsgutschrift (Objekt 14) an.
- Das Add-on liest den Beleg, prüft die DGI-Regeln, die sich lokal prüfen lassen, und erzeugt das NUC-JSON.
- Es sendet das JSON per POST an Digifact (
/api/v2/transform/nuc_json, Query-ParameterTAXID,FORMAT,USERNAME). Digifact wandelt es in das DGI-XML um, signiert es und holt die Autorisierung ein. - Die Antwort enthält CUFE, Protokoll, Autorisierungsdatum und QR-URL. Das Add-on schreibt sie in benutzerdefinierte Felder an
OINV/ORINund hängt XML und PDF an den Beleg an.
Zwei Designentscheidungen haben mir den meisten Ärger erspart:
- Eine Registerzeile pro Beleg (eine benutzerdefinierte Tabelle,
@FE_PA_DOC, mit dem Schlüssel13-<DocEntry>oder14-<DocEntry>). Zwei Arbeitsplätze, die gleichzeitig Belege anlegen, können so nie dieselbe Rechnung zweimal senden. - Erst abfragen, dann erneut senden. Ist beim Senden ein Timeout aufgetreten, fragt das Add-on zuerst bei Digifact nach, ob diese NumeroDF bereits existiert, und sendet erst dann erneut. Im Test lieferte ein Klick auf „Reintentar“ bei einer bereits autorisierten Rechnung denselben CUFE und sendete nichts.
Welche SAP-B1-Felder entsprechen welchen NUC-JSON-Feldern?
Das NUC-JSON unterscheidet Groß- und Kleinschreibung. Buyer.TaxID funktioniert, buyer.taxid nicht. Viele Werte stehen in Listen aus { "Name": ..., "Value": ... }-Objekten statt in einfachen Eigenschaften – das ist der erste Stolperstein für alle, die von FEL Guatemala oder DTE El Salvador kommen.
| NUC-JSON-Feld | Bedeutung | Herkunft in SAP B1 |
|---|---|---|
Header.DocType | 01 Rechnung, 03 Export, 04/06 Gutschrift, 05/07 Belastungsanzeige, 08, 09, 10 | Objekttyp (13/14), DocSubType = 'DN' für Belastungsanzeigen, plus ein Beleg-UDF für 02/08/09/10 |
Header.IssuedDateTime | Ausstellungsdatum und -uhrzeit, 2026-10-27T14:23:00-05:00 | Beim Senden ermittelt und in einem UDF gespeichert (U_FE_FechaEmi). Gutschriften brauchen den Wert später |
AdditionalIssueDocInfo → NumeroDF | 10-stellige Fiskalnummer, mit Nullen aufgefüllt, beginnt nie neu | Eigener Zähler pro Fakturierungspunkt. Verwenden Sie DocNum nicht ungeprüft, wenn Sie mehrere Nummernkreise haben |
PtoFactDF | Fakturierungspunkt, 3 Ziffern, nicht 000 | Einstellung im Add-on |
CodigoSeguridad | Zufällige 9 Ziffern, Teil des CUFE, ungleich NumeroDF | Pro Beleg erzeugt |
Seller.TaxID, TaxIDType, DigitoVerificador | RUC des Ausstellers, 1 natürliche / 2 juristische Person, DV | Einstellungen im Add-on (ein Mandant, ein RUC) |
Seller.BranchInfo.Code | 0000 Hauptsitz, ab 0001 Filialen | Einstellung im Add-on |
Buyer.TaxID | RUC, oder CF für consumidor final, oder EXTRANJERO | OCRD.LicTradNum |
TipoReceptor | 01 contribuyente, 02 consumidor final, 03 gobierno, 04 extranjero | GP-UDF U_FE_TipoRec |
Buyer.TaxIDType / DigitoVerificador | Natürliche oder juristische Person, DV des RUC | GP-UDFs U_FE_TipoRuc, U_FE_DV |
CodUbi | Code für Provinz-Distrikt-Corregimiento | GP-UDF U_FE_CodUbi |
Buyer.Name, E-Mail, Telefon | Name und Kontakt des Empfängers | OCRD.CardName, E_Mail, Phone1 |
Items[].Description, Qty | Positionstext und Menge | INV1.Dscription, Quantity |
Items[].Price | Stückpreis vor Rabatt | INV1.PriceBefDi |
Discounts.Discount[].Amount | Rabatt pro Einheit in Balboas, kein Prozentsatz | PriceBefDi - Price |
Codes → CodCPBSabr / CodCPBScmp | CPBS-Code für Waren und Dienstleistungen (2 und 4 Stellen) | Artikel-UDF U_FE_CPBS an OITM |
Taxes.Tax[].Code | ITBMS 00 = 0 %, 01 = 7 %, 02 = 10 %, 03 = 15 % | Aus INV1.VatPrcnt |
Taxes.Tax[].Amount | Steuerbetrag der Position | INV1.VatSum (oder VatSumFrgn) |
Totals.TotalItem | Positionssumme inklusive Steuer | LineTotal + VatSum |
Payments | Typ 02 ohne Zahlungsziel; mit Zahlungsziel Typ 01 plus eine PLAZO-Zeile mit Fälligkeitsdatum | Tage aus OCTG zum GroupNum, DocDueDate |
Zwei Details aus den Tests, die die Spezifikation nicht deutlich macht:
- Positionsbeträge, nicht Kopfbeträge. Bilden Sie jede Summe aus den Positionen und lassen Sie den Kopf deren Summe sein. Bei Rechnungen mit mehreren Steuersätzen (0, 7 und 10 % in einem Beleg) und bei einer Rechnung mit 105 Positionen hatte ich null Abweichungen, weil ich jede Position zuerst auf zwei Nachkommastellen gerundet und dann addiert habe.
- Mandanten mit Fremdwährung. Ist die Hauswährung des Mandanten nicht USD, stehen
DocTotal,LineTotalundVatSumin Hauswährung. Die E-Rechnung muss die Belegwährung enthalten, lesen Sie also stattdessenDocTotalFC,TotalFrgnundVatSumFrgn. Mein Testmandant hatte GBP als Hauswährung – so ist das aufgefallen.
Welche benutzerdefinierten Felder brauchen Sie in SAP Business One?
Eingaben (vom Benutzer oder im GP-Stamm gepflegt): U_FE_TipoRec, U_FE_TipoRuc, U_FE_DV, U_FE_CodUbi an OCRD; U_FE_CPBS an OITM; U_FE_Incoterm, U_FE_PuertoEmb und U_FE_TipoDoc am Beleg.
Ausgaben (vom Add-on an OINV und ORIN geschrieben): Status, CUFE, Protokoll, Autorisierungsdatum, QR-URL, NumeroDF, gesendetes Ausstellungsdatum und -uhrzeit, Fehlertext, Anzahl der Versuche und Stornogrund. Die QR-URL hat etwa 560 Zeichen; sie braucht also ein Memofeld, kein alphanumerisches Feld mit 254 Zeichen.
Viele Kunden haben aus einer früheren Lokalisierung bereits eigene Felder für RUC-Typ oder DV. In meiner Einstellungsmaske können Sie jeden Schlüssel auf ein vorhandenes Feld verweisen lassen, statt ein Duplikat anzulegen. Was Sie auch tun: Legen Sie die Felder über die DI API oder die Oberfläche an, nie mit ALTER TABLE.
Vor dem Produktivstart führe ich diese Prüfung aus. Sie listet die Stammdaten auf, die abgelehnt würden, bevor überhaupt etwas beim PAC ankommt. Zuerst die SQL-Server-Version:
-- Customers that will fail: contribuyente/gobierno without RUC, DV or location code
SELECT C.CardCode, C.CardName, C.LicTradNum, C.U_FE_TipoRec, C.U_FE_DV, C.U_FE_CodUbi
FROM OCRD C
WHERE C.CardType = 'C'
AND ISNULL(C.U_FE_TipoRec, '01') IN ('01', '03')
AND (ISNULL(C.LicTradNum, '') = '' OR ISNULL(C.U_FE_DV, '') = '' OR ISNULL(C.U_FE_CodUbi, '') = '');
-- Items sold in the last 90 days without a CPBS code
SELECT DISTINCT L.ItemCode, I.ItemName
FROM INV1 L
INNER JOIN OINV H ON H.DocEntry = L.DocEntry
INNER JOIN OITM I ON I.ItemCode = L.ItemCode
WHERE H.DocDate >= DATEADD(DAY, -90, GETDATE())
AND ISNULL(I.U_FE_CPBS, '') = '';
Die SAP-HANA-Version (Bezeichner in Anführungszeichen, IFNULL, ADD_DAYS):
SELECT C."CardCode", C."CardName", C."LicTradNum", C."U_FE_TipoRec", C."U_FE_DV", C."U_FE_CodUbi"
FROM "OCRD" C
WHERE C."CardType" = 'C'
AND IFNULL(C."U_FE_TipoRec", '01') IN ('01', '03')
AND (IFNULL(C."LicTradNum", '') = '' OR IFNULL(C."U_FE_DV", '') = '' OR IFNULL(C."U_FE_CodUbi", '') = '');
SELECT DISTINCT L."ItemCode", I."ItemName"
FROM "INV1" L
INNER JOIN "OINV" H ON H."DocEntry" = L."DocEntry"
INNER JOIN "OITM" I ON I."ItemCode" = L."ItemCode"
WHERE H."DocDate" >= ADD_DAYS(CURRENT_DATE, -90)
AND IFNULL(I."U_FE_CPBS", '') = '';
Wenn Sie heute nur SQL-Server-Abfragen haben, übernimmt der SQL-zu-HANA-Konverter die meisten Dialektänderungen.
Wie verweisen Gutschriften auf die ursprüngliche Rechnung?
Eine Ausgangsgutschrift in SAP B1, die auf einer Rechnung basiert (RIN1.BaseType = 13, BaseEntry = <DocEntry der Rechnung>), wird zum DGI-Typ 04. Sie muss in AdditionalInfo drei Werte enthalten: den Namen des Ausstellers (NombEmRef), Ausstellungsdatum und -uhrzeit der ursprünglichen E-Rechnung (FechaDFRef) und deren CUFE (CUFERef). Deshalb muss die Ausstellungszeit beim Senden der Rechnung gespeichert werden. Aus dem DocDate lässt sie sich später nicht rekonstruieren.
Eine Gutschrift ohne Basisbeleg oder mit Bezug auf eine Rechnung von vor Ihrem Produktivstart ist eine generische Gutschrift, Typ 06, ohne Referenz. Welche Gutschriften eine Basisrechnung haben, sehen Sie in der Tabelle ORIN (Ausgangsgutschrift) und ihren RIN1-Positionen.
Die DGI-Regeln, die mich am härtesten getroffen haben und die ich heute alle vor dem Senden in SAP prüfe:
| DGI-Regel | Bedeutung | Prüfung in SAP B1 |
|---|---|---|
| 1710 | Die Gutschrift muss denselben Empfänger haben wie die Rechnung | Den Käufer aus dem JSON übernehmen, das für die Rechnung gesendet wurde, nicht aus dem heutigen GP-Stamm |
| 1711 | Gutschrift höher als die Rechnung | Mit der Summe der Basisrechnung vergleichen |
| 1714 | Gutschrift mehr als 180 Tage nach der Rechnung ausgestellt | DocDate der Gutschrift gegenüber der Rechnung |
| 1717 | Alle Gutschriften zusammen übersteigen Rechnung plus Belastungsanzeigen | Die bereits autorisierten Gutschriften summieren, die über Basispositionen in RIN1/INV1 verknüpft sind |
| 1718 | Gutschrift zu einer stornierten (anulada) Rechnung | Status der Basisrechnung |
| 1720 | Für die referenzierte Rechnung ist kein Ausstellungsdatum/-uhrzeit gespeichert | Das Feld FechaEmi der Rechnung |
Eine Gutschrift zu einer Basisrechnung, die noch nicht autorisiert ist, ist kein Fehler. Mein Add-on hält sie zurück, bis die Rechnung ihren CUFE hat, und sendet sie dann.
Was verursacht die häufigsten Ablehnungen bei Panama FE?
Aus den Sandbox-Tests, in der Reihenfolge, in der sie mir begegnet sind:
- Behörde als Empfänger (03) mit normalem RUC. Regel 1604: Der RUC muss in der DGI-Tabelle der Behörden (Tabla 30) stehen. Ist der Kunde nicht auf dieser Liste, verwenden Sie Empfängertyp 01. Nach Korrektur des RUC hat ein einfacher erneuter Versuch dieselbe Rechnung autorisiert.
- Consumidor final mit dem RUC einer juristischen Person. Regel 1621: Ein juristischer RUC (
TaxIDType2) kann nicht Empfängertyp 02 sein. - Export oder Auslandsgeschäft ohne INCOTERM. Bei den Typen 03 und 10 meldete die Sandbox, dass die Lieferbedingungen (
CondEntr) fehlten. Erfassen Sie den INCOTERM in einem Beleg-UDF und senden Sie ihn inAdditionalInfo. - Das Zeichen
<in einer Artikelbeschreibung. Eine Testrechnung kam mit „XSLT failed“ zurück, weil der Positionstext ein<enthielt. Maskieren oder ersetzen Sie es vor dem Senden.ñ,á,&,"und>wurden alle akzeptiert, auch ein Kunde namens „Compañía Ñandú & Hijos“. - Rabatt auf Belegebene.
OINV.DiscSumhat in der Positionsstruktur keinen sauberen Platz. Mein Add-on sperrt einen Beleg, der noch einen Belegrabatt hat, und verlangt stattdessen Positionsrabatte. Dasselbe Belegrabatt-Problem verzerrt auch Umsatzberichte, siehe warum Umsatzsummen in SAP B1 nicht übereinstimmen.
Wie stornieren (anular) Sie eine E-Rechnung aus SAP Business One?
Die Stornierung geht an den Endpunkt CancelFePA von Digifact, mit RUC des Ausstellers, CUFE, einem Grund (Motivo) und dem Benutzer. Zwei Dinge habe ich in der Testumgebung gemessen:
- Direkt nach der Autorisierung scheitert die Stornierung mit
{"Codigo":9019,"Anulado":false,"Mensaje":"Anulacion incorrecta. Verifique si el CUFE pertenece a una FE existente"}. Drei bis acht Minuten später wurde derselbe Aufruf angenommen. Mein Add-on versucht es einmal pro Minute erneut, statt dem Benutzer einen Fehler anzuzeigen. - Kurze Gründe scheitern mit demselben Fehler 9019. Zwanzig Zeichen oder weniger wurden immer abgelehnt, 25 oder mehr immer angenommen, obwohl das technische Merkblatt der DGI 15 bis 1000 Zeichen zulässt. Ich erzwinge im Formular mindestens 25 Zeichen.
In SAP B1 sollte Daten > Stornieren bei einer autorisierten Rechnung zuerst bei der DGI stornieren. Lehnt die DGI ab, sperren Sie die Stornierung in SAP – sonst zeigt SAP die Rechnung als storniert, während die DGI sie weiterhin als gültig führt. Eine Rechnung, die die DGI nie erreicht hat, kann direkt in SAP storniert werden.
Wenn Sie das selbst als Add-on entwickeln: Die Muster für Ereignisbehandlung, Paketierung und Buchen über die DI API stehen in meinem Leitfaden zur Add-on-Entwicklung für SAP Business One, die Felder der oben genannten Tabellen in der SAP-B1-Tabellenreferenz.
Was ist noch offen?
Notfallbetrieb (TipoEmision 02/04) und andere Währungen als USD sind noch nicht in meinem Add-on. Belastungsanzeigen (05 und 07) wurden in der Sandbox autorisiert, aber ein Mandant mit britischer Lokalisierung kann sie nicht über die DI API buchen (DocumentSubType = DN wird abgelehnt). Testen Sie sie deshalb in einem Mandanten mit Lokalisierung für Panama oder Lateinamerika.
Wenn Sie SAP Business One in Panama betreiben und FE über Digifact benötigen, schildern Sie mir Ihre Umgebung. Dieselbe Art von Integration habe ich für FEL Guatemala, DTE El Salvador, SRI Ecuador und ZATCA Saudi-Arabien umgesetzt.
Quellen
Passende Leistungen
Häufige Fragen
Brauche ich in Panama einen PAC, um aus SAP Business One elektronische Rechnungen auszustellen?
Für eine ERP-Integration praktisch ja. SAP Business One kommuniziert nicht direkt mit der DGI. Der Beleg geht an einen PAC (Proveedor de Autorización Calificado), der ihn prüft, autorisiert und an die DGI weiterleitet. Mein Add-on nutzt den PAC Digifact und dessen NUC-JSON-API.
Welche SAP-Business-One-Belege werden zu welchen DGI-Dokumenttypen?
Eine Ausgangsrechnung ist Typ 01 (oder 03 Export, 08 zona franca, 09 reembolso, 10 operación extranjera, wenn Sie das festlegen). Eine Ausgangsgutschrift, die auf einer elektronisch ausgestellten Rechnung basiert, ist Typ 04; ohne referenzierte Rechnung ist sie Typ 06. Belastungsanzeigen sind 05 und 07.
Warum verweigert die DGI die Stornierung einer Rechnung, die ich gerade ausgestellt habe?
In der Testumgebung von Digifact antwortete CancelFePA in den ersten Minuten nach der Autorisierung mit Code 9019, ebenso immer dann, wenn der Grund (Motivo) 20 Zeichen oder kürzer war. Etwa 3 Minuten zu warten und einen Grund mit 25 oder mehr Zeichen anzugeben, hat jedes Mal funktioniert.
Bereit für den Start?
Sagen Sie uns, was Sie brauchen. Sie erhalten eine klare technische Antwort, einen festen Leistungsumfang und einen Preis, in der Regel innerhalb von 24 Stunden.
