Factura electrónica de Panamá desde SAP Business One: mapeo de campos NUC-JSON y rechazos de la DGI

Por Zain Abbas, Kodenova · Actualizado el

Respuesta cortaPara emitir una factura electrónica de Panamá desde SAP Business One a través del PAC Digifact, se envía un NUC-JSON por documento: Header (DocType, IssuedDateTime, NumeroDF, CodigoSeguridad), Seller, Buyer (TipoReceptor, RUC, DV, CodUbi), Items con código ITBMS 00/01/02/03 para 0/7/10/15 % y Payments. SAP B1 ya contiene la mayor parte en OINV, INV1, OCRD y OITM. Usted agrega algunos campos de usuario (tipo de receptor, DV, código de ubicación, CPBS) y guarda el CUFE, el protocolo y la URL del QR que se reciben de vuelta.

Para emitir una factura electrónica de Panamá (Factura Electrónica, FE) desde SAP Business One a través del PAC Digifact, se envía un documento NUC-JSON por cada factura o nota de crédito. La mayor parte de los datos ya está en OINV, INV1, OCRD y OITM. Lo que SAP B1 no trae de forma estándar es el tipo de receptor, el dígito verificador del RUC (DV), el código de ubicación (CodUbi) y el código CPBS del artículo, así que esos se convierten en campos de usuario. El PAC responde con un CUFE, un protocolo de autorización y una URL del QR, que se escriben de vuelta en el documento.

Esta guía es el mapeo que uso en mi add-on de SAP Business One para Panamá. Se probó el 27 de octubre de 2026 en una empresa de SAP B1 10 sobre SQL Server contra el sandbox de Digifact: 34 escenarios, desde una factura a consumidor con 7 % hasta una factura de 105 líneas, exportaciones, zona franca, notas de crédito y anulaciones. Para la visión comercial, consulte facturación electrónica en Panamá para SAP Business One.

¿Cómo funciona el flujo de SAP Business One a la DGI?

  1. El usuario agrega una factura de clientes (objeto 13) o una nota de crédito de clientes (objeto 14) en SAP B1 como siempre.
  2. El add-on lee el documento, revisa las reglas de la DGI que puede validar localmente y arma el NUC-JSON.
  3. Envía el JSON a Digifact (/api/v2/transform/nuc_json, parámetros de consulta TAXID, FORMAT, USERNAME). Digifact lo convierte en el XML de la DGI, lo firma y obtiene la autorización.
  4. La respuesta trae el CUFE, el protocolo, la fecha de autorización y la URL del QR. El add-on los escribe en campos de usuario de OINV/ORIN y adjunta el XML y el PDF al documento.

Dos decisiones de diseño me ahorraron la mayoría de los problemas:

  • Un registro por documento (una tabla de usuario, @FE_PA_DOC, con clave 13-<DocEntry> o 14-<DocEntry>). Dos estaciones de trabajo que agregan documentos al mismo tiempo nunca pueden enviar la misma factura dos veces.
  • Consultar antes de reenviar. Si el envío se agotó por tiempo de espera, el add-on primero pregunta a Digifact si ese NumeroDF ya existe, y solo entonces vuelve a enviar. En la prueba, presionar “Reintentar” en una factura ya autorizada devolvió el mismo CUFE y no envió nada.

¿Qué campos de SAP B1 corresponden a qué campos del NUC-JSON?

El NUC-JSON distingue mayúsculas y minúsculas. Buyer.TaxID funciona, buyer.taxid no. Muchos valores van en listas de objetos { "Name": ..., "Value": ... } en lugar de propiedades simples, que es lo primero que confunde a quienes vienen de FEL de Guatemala o DTE de El Salvador.

Campo NUC-JSONQué esDe dónde sale en SAP B1
Header.DocType01 factura, 03 exportación, 04/06 nota de crédito, 05/07 nota de débito, 08, 09, 10Tipo de objeto (13/14), DocSubType = 'DN' para notas de débito, más un UDF del documento para 02/08/09/10
Header.IssuedDateTimeFecha y hora de emisión, 2026-10-27T14:23:00-05:00Se toma al momento del envío y se guarda en un UDF (U_FE_FechaEmi). Las notas de crédito lo necesitan después
AdditionalIssueDocInfo → NumeroDFNúmero fiscal de 10 dígitos, con ceros a la izquierda, nunca se reiniciaContador propio por punto de facturación. No reutilice DocNum a ciegas si tiene varias series
PtoFactDFPunto de facturación, 3 dígitos, distinto de 000Configuración del add-on
CodigoSeguridad9 dígitos aleatorios, parte del CUFE, distinto de NumeroDFSe genera por documento
Seller.TaxID, TaxIDType, DigitoVerificadorRUC del emisor, 1 natural / 2 jurídico, DVConfiguración del add-on (una empresa, un RUC)
Seller.BranchInfo.Code0000 casa matriz, 0001+ sucursalesConfiguración del add-on
Buyer.TaxIDRUC, o CF para consumidor final, o EXTRANJEROOCRD.LicTradNum
TipoReceptor01 contribuyente, 02 consumidor final, 03 gobierno, 04 extranjeroUDF del socio de negocios U_FE_TipoRec
Buyer.TaxIDType / DigitoVerificadorNatural o jurídico, DV del RUCUDF del socio de negocios U_FE_TipoRuc, U_FE_DV
CodUbiCódigo de provincia-distrito-corregimientoUDF del socio de negocios U_FE_CodUbi
Buyer.Name, email, teléfonoNombre y contacto del receptorOCRD.CardName, E_Mail, Phone1
Items[].Description, QtyTexto y cantidad de la líneaINV1.Dscription, Quantity
Items[].PricePrecio unitario antes del descuentoINV1.PriceBefDi
Discounts.Discount[].AmountDescuento por unidad en balboas, no un porcentajePriceBefDi - Price
Codes → CodCPBSabr / CodCPBScmpCódigo CPBS de bienes y servicios (2 y 4 dígitos)UDF de artículo U_FE_CPBS en OITM
Taxes.Tax[].CodeITBMS 00 = 0 %, 01 = 7 %, 02 = 10 %, 03 = 15 %A partir de INV1.VatPrcnt
Taxes.Tax[].AmountImporte del impuesto de la líneaINV1.VatSum (o VatSumFrgn)
Totals.TotalItemTotal de la línea con impuestoLineTotal + VatSum
PaymentsTipo 02 sin condiciones de crédito; con condiciones de crédito, tipo 01 más una línea PLAZO con la fecha de vencimientoDías de OCTG según GroupNum, DocDueDate

Dos detalles de las pruebas que la especificación no deja claros:

  • Importes de línea, no de cabecera. Arme cada total a partir de las líneas y deje que la cabecera sea su suma. Tuve cero diferencias en facturas con varias tasas (0, 7 y 10 % en un mismo documento) y en una factura de 105 líneas redondeando primero cada línea a dos decimales y sumando después.
  • Empresas con otra moneda local. Si la moneda local de la empresa no es USD, DocTotal, LineTotal y VatSum están en moneda local. La factura electrónica debe llevar la moneda del documento, así que lea DocTotalFC, TotalFrgn y VatSumFrgn en su lugar. Mi empresa de prueba tenía GBP como moneda local, y así fue como apareció esto.

¿Qué campos de usuario necesita en SAP Business One?

Entradas (las llena el usuario o el maestro de socios de negocios): U_FE_TipoRec, U_FE_TipoRuc, U_FE_DV, U_FE_CodUbi en OCRD; U_FE_CPBS en OITM; U_FE_Incoterm, U_FE_PuertoEmb y U_FE_TipoDoc en el documento.

Salidas (las escribe el add-on en OINV y ORIN): estado, CUFE, protocolo, fecha de autorización, URL del QR, NumeroDF, fecha/hora de emisión enviada, texto de error, intentos y el motivo de anulación. La URL del QR tiene unos 560 caracteres, así que necesita un campo memo, no uno alfanumérico de 254 caracteres.

Muchos clientes ya tienen sus propios campos para el tipo de RUC o el DV de una localización anterior. Mi pantalla de configuración le permite asignar cada clave a un campo existente en lugar de crear un duplicado. Haga lo que haga, cree los campos mediante la DI API o la interfaz, nunca con ALTER TABLE.

Antes de la salida en vivo ejecuto esta verificación. Lista los datos maestros que serán rechazados antes de que algo llegue al PAC. Primero la versión de SQL Server:

-- 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, '') = '';

Versión para SAP HANA (identificadores entre comillas, 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", '') = '';

Si hoy solo tiene consultas de SQL Server, el convertidor de SQL a HANA resuelve la mayoría de los cambios de dialecto.

¿Cómo hacen referencia las notas de crédito a la factura original?

Una nota de crédito en SAP B1 basada en una factura (RIN1.BaseType = 13, BaseEntry = <invoice DocEntry>) se convierte en el tipo 04 de la DGI. Debe llevar tres valores en AdditionalInfo: el nombre del emisor (NombEmRef), la fecha/hora de emisión de la factura electrónica original (FechaDFRef) y su CUFE (CUFERef). Por eso la hora de emisión debe guardarse cuando se envía la factura. No se puede reconstruir después a partir de DocDate.

Una nota de crédito sin documento base, o basada en una factura anterior a su fecha de salida en vivo, es una nota genérica, tipo 06, sin referencia. Qué notas de crédito tienen una factura base se puede ver en la tabla ORIN (nota de crédito de clientes) y sus líneas RIN1.

Las reglas de la DGI que más problemas dieron, y que ahora reviso todas en SAP antes de enviar:

Regla DGIQué significaVerificación en SAP B1
1710La nota debe tener el mismo receptor que la facturaTome el comprador del JSON que se envió para la factura, no de los datos maestros actuales del socio de negocios
1711Nota de crédito mayor que la facturaCompare con el total de la factura base
1714Nota emitida más de 180 días después de la facturaDocDate de la nota frente a la factura
1717La suma de créditos supera la factura + notas de débitoSume las notas autorizadas ya vinculadas mediante las líneas base de RIN1/INV1
1718Nota contra una factura anuladaEstado de la factura base
1720La factura referenciada no tiene fecha/hora de emisión guardadaEl campo FechaEmi de la factura

Una nota de crédito sobre una factura base que todavía no está autorizada no es un error. Mi add-on la retiene hasta que la factura tenga su CUFE y luego la envía.

¿Qué causa los rechazos más comunes de la FE en Panamá?

De las pruebas en sandbox, en el orden en que me los encontré:

  • Receptor gobierno (03) con un RUC normal. Regla 1604: el RUC debe estar en la tabla de entidades gubernamentales de la DGI (Tabla 30). Si el cliente no está en esa lista, use el tipo de receptor 01. Después de corregir el RUC, un simple reintento autorizó la misma factura.
  • Consumidor final con un RUC de persona jurídica. Regla 1621: un RUC jurídico (TaxIDType 2) no puede ser tipo de receptor 02.
  • Exportación u operación extranjera sin INCOTERM. Para los tipos 03 y 10 el sandbox respondió que faltaban las condiciones de entrega (CondEntr). Ponga el INCOTERM en un UDF del documento y envíelo en AdditionalInfo.
  • El carácter < en la descripción de un artículo. Una factura de prueba volvió con “XSLT failed” (falló la transformación XSLT) por un < en el texto de la línea. Escápelo o reemplácelo antes de enviar. ñ, á, &, " y > fueron aceptados, incluido un cliente llamado “Compañía Ñandú & Hijos”.
  • Descuento a nivel de documento. OINV.DiscSum no tiene un lugar limpio en la estructura de los ítems. Mi add-on bloquea un documento que todavía tiene un descuento de cabecera y pide descuentos por línea en su lugar. El mismo problema del descuento de cabecera distorsiona también los reportes de ventas; consulte por qué no cuadran los totales de ventas en SAP B1.

¿Cómo se anula una factura electrónica desde SAP Business One?

La anulación va al endpoint CancelFePA de Digifact con el RUC del emisor, el CUFE, un motivo (Motivo) y el usuario. Dos cosas que medí en el ambiente de pruebas:

  1. Justo después de la autorización, la anulación falla con {"Codigo":9019,"Anulado":false,"Mensaje":"Anulacion incorrecta. Verifique si el CUFE pertenece a una FE existente"}. Entre tres y ocho minutos después, la misma llamada fue aceptada. Mi add-on reintenta una vez por minuto en lugar de mostrarle un error al usuario.
  2. Los motivos cortos fallan con el mismo 9019. Veinte caracteres o menos siempre fueron rechazados y 25 o más siempre aceptados, aunque la ficha técnica de la DGI permite de 15 a 1000. Yo exijo un mínimo de 25 caracteres en el formulario.

En SAP B1, Datos > Cancelar (Data > Cancel) sobre una factura autorizada debe anular en la DGI primero. Si la DGI lo rechaza, bloquee la cancelación en SAP; de lo contrario, SAP muestra la factura como cancelada mientras la DGI todavía la considera válida. Una factura que nunca llegó a la DGI se puede cancelar directamente en SAP.

Si usted mismo está construyendo esto como add-on, los patrones de manejo de eventos, empaquetado y contabilización con DI están en mi guía de desarrollo de add-ons para SAP Business One, y los campos de las tablas anteriores están en la referencia de tablas de SAP B1.

¿Qué queda pendiente?

El modo de contingencia (TipoEmision 02/04) y las monedas distintas de USD todavía no están en mi add-on. Las notas de débito (05 y 07) se autorizaron en el sandbox, pero una empresa con localización del Reino Unido no puede contabilizarlas desde la DI API (DocumentSubType = DN es rechazado), así que pruébelas en una empresa con localización de Panamá o de América Latina.

Si usa SAP Business One en Panamá y necesita FE a través de Digifact, cuénteme sobre su instalación. He hecho el mismo tipo de integración para FEL de Guatemala, DTE de El Salvador, SRI de Ecuador y ZATCA de Arabia Saudita.

Fuentes

Servicios relacionados

Preguntas frecuentes

Preguntas frecuentes

¿Necesito un PAC para emitir facturas electrónicas desde SAP Business One en Panamá?

Para una integración con el ERP, en la práctica sí. SAP Business One no se comunica directamente con la DGI. El documento va a un PAC (Proveedor de Autorización Calificado), que lo valida, lo autoriza y lo transmite a la DGI. Mi add-on usa el PAC Digifact y su API NUC-JSON.

¿Qué documentos de SAP Business One se convierten en qué tipos de documento de la DGI?

Una factura de clientes es tipo 01 (o 03 exportación, 08 zona franca, 09 reembolso, 10 operación extranjera cuando usted lo indica). Una nota de crédito de clientes basada en una factura ya emitida electrónicamente es 04; sin factura referenciada es 06. Las notas de débito son 05 y 07.

¿Por qué la DGI rechaza anular una factura que acabo de emitir?

En el ambiente de pruebas de Digifact, CancelFePA respondió con el código 9019 durante unos minutos después de la autorización, y también siempre que el motivo (Motivo) tenía 20 caracteres o menos. Esperar unos 3 minutos y escribir un motivo de 25 caracteres o más funcionó todas las veces.

¿Listo para empezar?

Cuéntenos lo que necesita. Recibirá una respuesta técnica clara, un alcance definido y un precio fijo, normalmente en 24 horas.