Skip to main content

Descripción

Las Notas de Débito (tipo documento 08) se utilizan para aumentar el valor de facturas o boletas previamente emitidas. Se aplican en casos como:
  • Intereses por mora
  • Gastos adicionales no incluidos originalmente
  • Penalidades
  • Aumento en el valor de la operación
El sistema genera automáticamente la serie según el documento afectado:
  • FC01: Para notas de débito que afectan Facturas (01)
  • BC01: Para notas de débito que afectan Boletas (03)

Flujo de Trabajo

  1. Crear nota de débito: POST /api/notas-debito - Genera el registro y XML firmado
  2. Enviar a SUNAT: POST /api/notas-debito/{id}/enviar - Envío sincrónico vía SOAP
  3. Obtener CDR: GET /api/notas-debito/{id}/cdr - Descarga la constancia de recepción
A diferencia de las notas de crédito, las notas de débito NO anulan la venta original. Simplemente registran un cargo adicional.

POST /api/notas-debito

Crea una nueva nota de débito asociada a una venta existente.

Request Body

id_venta
integer
required
ID de la venta a afectar (factura o boleta existente)
motivo_id
integer
required
ID del motivo de la nota de débito. Obtener lista desde GET /api/notas-debito/motivos
monto_total
decimal
required
Monto total del cargo adicional (incluye IGV). Debe ser mayor a 0.01
descripcion_motivo
string
Descripción personalizada del motivo (opcional, usa la descripción del motivo por defecto si se omite)

Motivos de Nota de Débito (Catálogo SUNAT 10)

CódigoDescripción
01Intereses por mora
02Aumento en el valor
03Penalidades / otros conceptos

Lógica del Servidor

  1. Valida que la venta exista y pertenezca a la empresa del usuario
  2. Determina la serie automáticamente:
    • Si tipo_doc_afectado = '01' (Factura) → Serie FC01
    • Si tipo_doc_afectado = '03' (Boleta) → Serie BC01
  3. Genera el número correlativo (máximo + 1)
  4. Calcula el desglose de IGV:
    $igvRate = 0.18; // Configurable por empresa
    $subtotal = round($monto_total / ($igvRate + 1), 2);
    $igv = round($monto_total - $subtotal, 2);
    
  5. Genera el XML UBL 2.1 firmado digitalmente usando Greenter
  6. Calcula el hash CPE del XML
  7. Almacena el XML en storage/app/sunat/xml/{ruc}/

Response

success
boolean
Indica si la operación fue exitosa
data
object
Objeto de la nota de débito creada
xml
object
Información sobre el XML generado

Ejemplo de Request

{
  "id_venta": 145,
  "motivo_id": 1,
  "monto_total": 23.60,
  "descripcion_motivo": "Intereses por pago fuera de fecha"
}

Ejemplo de Response (201 Created)

{
  "success": true,
  "data": {
    "id": 12,
    "id_venta": 145,
    "motivo_id": 1,
    "serie": "FC01",
    "numero": 8,
    "tipo_doc_afectado": "01",
    "serie_num_afectado": "F001-145",
    "descripcion_motivo": "Intereses por pago fuera de fecha",
    "monto_subtotal": "20.00",
    "monto_igv": "3.60",
    "monto_total": "23.60",
    "moneda": "PEN",
    "fecha_emision": "2026-03-06",
    "estado": "pendiente",
    "hash_cpe": "mK3qWzR8pLm...",
    "xml_url": "sunat/xml/20612706702/20612706702-08-FC01-00000008.xml",
    "nombre_xml": "20612706702-08-FC01-00000008",
    "id_empresa": 1,
    "id_usuario": 5,
    "venta": {
      "id_venta": 145,
      "serie": "F001",
      "numero": 145,
      "total": "100.00",
      "cliente": {
        "documento": "20123456789",
        "datos": "EMPRESA EJEMPLO SAC"
      }
    },
    "motivo": {
      "id": 1,
      "tipo": "ND",
      "codigo_sunat": "01",
      "descripcion": "Intereses por mora"
    }
  },
  "xml": {
    "success": true,
    "nombre_archivo": "20612706702-08-FC01-00000008",
    "hash": "mK3qWzR8pLm..."
  }
}

POST /api/notas-debito//enviar

Envía la nota de débito generada a SUNAT para su aceptación.

Path Parameters

id
integer
required
ID de la nota de débito a enviar

Flujo SUNAT (Sincrónico)

  1. Lee el XML firmado desde storage/app/sunat/xml/{ruc}/
  2. Se autentica con SUNAT usando credenciales SOL (RUC + usuario + clave)
  3. Envía el XML vía SOAP a la API de SUNAT
  4. Recibe el CDR (Constancia de Recepción) inmediatamente
  5. Almacena el CDR en storage/app/sunat/cdr/{ruc}/R-{nombre}.zip
  6. Actualiza el estado de la nota según la respuesta

Validaciones

  • La nota de débito debe tener XML generado (nombre_xml no nulo)
  • El archivo XML debe existir en el servidor

Response (Éxito)

success
boolean
true si SUNAT aceptó la nota de débito
codigo
string
Código de respuesta de SUNAT (ej: “0” = aceptado, “0100” = aceptado con observaciones)
mensaje
string
Descripción de la respuesta de SUNAT

Response (Error)

success
boolean
false si SUNAT rechazó la nota
codigo
string
Código de error de SUNAT
message
string
Descripción del error

Ejemplo de Response (Éxito)

{
  "success": true,
  "codigo": "0",
  "mensaje": "La Nota de Débito numero FC01-00000008, ha sido aceptada"
}

Ejemplo de Response (Error)

{
  "success": false,
  "codigo": "2324",
  "message": "El documento afectado por la nota no existe o no está aceptado"
}

GET /api/notas-debito

Obtiene lista paginada de notas de débito de la empresa.

Query Parameters

page
integer
default:"1"
Número de página

Response

Objeto de paginación Laravel con 15 items por página.

GET /api/notas-debito/

Obtiene detalle completo de una nota de débito específica.

Path Parameters

id
integer
required
ID de la nota de débito

GET /api/notas-debito/motivos

Obtiene la lista de motivos disponibles para notas de débito.

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "tipo": "ND",
      "codigo_sunat": "01",
      "descripcion": "Intereses por mora",
      "estado": true
    },
    {
      "id": 2,
      "tipo": "ND",
      "codigo_sunat": "02",
      "descripcion": "Aumento en el valor",
      "estado": true
    },
    {
      "id": 3,
      "tipo": "ND",
      "codigo_sunat": "03",
      "descripcion": "Penalidades / otros conceptos",
      "estado": true
    }
  ]
}

Notas Técnicas

Integración con Greenter

El sistema utiliza la librería Greenter para:
  • Construir objetos UBL 2.1 conformes a SUNAT (tipo documento “08”)
  • Firmar digitalmente el XML con certificado PEM
  • Enviar vía SOAP al webservice de SUNAT
  • Procesar la respuesta CDR
Ver SunatService::generarNotaDebitoXml() (línea 446) y enviarNotaDebito() (línea 508).

Diferencia con Nota de Crédito

AspectoNota de CréditoNota de Débito
Tipo documento0708
EfectoDisminuye/anulaAumenta
MontoCopia de ventaLibre (usuario lo define)
Venta originalSe marca como anuladaPermanece activa

Cálculo de IGV

El IGV se calcula automáticamente desde el monto_total proporcionado:
$igvRate = (float) ($empresa->igv ?? 0.18); // 18% por defecto
$subtotal = round($monto_total / ($igvRate + 1), 2);
$igv = round($monto_total - $subtotal, 2);
Ejemplo:
  • monto_total = 118.00
  • igvRate = 0.18
  • subtotal = 100.00
  • igv = 18.00

Certificados Digitales

Se buscan en este orden:
  1. storage/app/sunat/certificados/{ruc}-cert.pem (específico de empresa)
  2. Certificado de prueba configurado en config/sunat.php

Ambientes SUNAT

Si empresa.modo !== 'production':
  • Usa RUC de prueba: 20000000001
  • Usuario SOL: MODDATOS
  • Clave SOL: moddatos
  • Endpoint beta de SUNAT

Líneas en el XML

Las notas de débito reutilizan las líneas de productos de la venta original para conformidad UBL, aunque el usuario solo especifica el monto total del cargo adicional. Ver SunatService::buildSaleDetailsFromVenta() (línea 1001).

Errores Comunes

CódigoDescripciónSolución
2324Documento afectado no existeVerificar que la factura/boleta esté aceptada por SUNAT
2800Serie no autorizadaVerificar configuración de series en SUNAT
1033Certificado inválidoRenovar certificado digital PEM
422XML no generadoLlamar primero a POST /api/notas-debito
422monto_total requeridoEl monto debe ser mayor a 0.01

Build docs developers (and LLMs) love