API
Cancelar Sector Primario

Cancelar Sector Primario

Esta sección detalla la operación para solicitar la cancelación de un CFDI emitido por un contribuyente del Sector Primario (SP).

Descripción de la Operación

Esta operación permite cancelar un CFDI de Sector Primario de forma simplificada. A diferencia de otros métodos de cancelación, este no requiere el envío de los Certificados de Sello Digital (CSD) del emisor. La autenticación se realiza a través del apikey.

Este método es exclusivo para los CFDI que fueron expedidos para el Sector Primario.

Parámetros de Entrada (Input)

Parámetro Tipo de Dato Descripción
apikey string Credencial de acceso al servicio (Solicita aquí).
rfcEmisor string RFC del contribuyente emisor del CFDI (del Sector Primario).
uuid string Folio Fiscal (UUID) del CFDI que se desea cancelar.

Parámetros de Salida (Output) - RespuestaCancelar

La respuesta de esta operación es idéntica a la de la operación cancelar2.

Atributo Tipo de Dato Descripción
code string Código de respuesta de la operación.
message string Mensaje detallado de la respuesta.
data string Acuse de cancelación en formato XML, devuelto por el SAT.
status string Indica el estado de la solicitud. Puede ser success (éxito) o error (fallido).

Ejemplo de Código

Solicitud (Request)

Herramienta svcutil

Descarga e instala la herramienta svcutil

Ejecuta el comando siguiente (DESARROLLO)

svcutil.exe https://dev.facturaloplus.com/ws/servicio.do?wsdl /out:ServicioTimbradoClient.cs /config:app.config

Esto genera dos archivos: ServicioTimbradoClient.cs y la configuración en app.config

Implementación

using System;
using System.Threading.Tasks;

 public class CancelarSPRequest
 {
      public string Apikey { get; set; }
      public string RfcEmisor { get; set; }
      public string Uuid { get; set; }
 }

 public async Task<RespuestaCancelar> CancelarSPAsync(CancelarSPRequest request)
  {
      using var client = new ServicioTimbradoWSPortTypeClient("ServicioTimbradoWSPort");
      try
      {
          var response = await client.cancelarSPAsync(request.Apikey, request.RfcEmisor, request.Uuid);
          return new RespuestaCancelar { Code = response.code, Message = response.message, Data = response.data, Status = response.status };
      }
      catch (Exception ex)
      {
         Console.WriteLine($"Error al cancelar CFDI de Sector Primario: {ex.Message}");
         throw;
      }
  }

  public class RespuestaCancelar
 {
    public string? Code { get; set; }
    public string? Message { get; set; }
    public string? Data { get; set; }
    public string? Status { get; set; }
 }

 // Ejemplo de uso
 public async Task EjemploUsoCancelarSPAsync()
 {
     var request = new CancelarSPRequest
     {
         Apikey = "TU_API_KEY_AQUI",
         RfcEmisor = "ABC010101XYZ",
         Uuid = "C3D4E08E-12F3-4B0C-8A4D-78E6B8E47113"
     };

     var resultado = await CancelarSPAsync(request);

     if (resultado?.Status == "success")
     {
         Console.WriteLine("¡Cancelación de CFDI SP Exitosa!");
         Console.WriteLine($"Mensaje: {resultado.Message}");
         Console.WriteLine("Acuse:");
         Console.WriteLine(resultado.Data);
     }
     else
     {
         Console.WriteLine($"Error: {resultado?.Code} - {resultado?.Message}");
     }
 }

Herramienta wsimport

Java incluye la herramienta wsimport en el JDK para generar las clases cliente a partir de un WSDL.

Ejecuta el siguiente comando en tu terminal para el ambiente de DESARROLLO:

wsimport -keep -p com.facturaloplus.cliente https://dev.facturaloplus.com/ws/servicio.do?wsdl

-keep: Conserva los archivos fuente .java generados.

-p: Especifica el paquete (package) donde se guardarán las clases.

Implementación

import java.util.concurrent.CompletableFuture;

public class CancelarSPService {

  // ... (Definición de ExecutorService, Logger, etc.)

  public CompletableFuture<RespuestaCancelar> cancelarSPAsync(String apiKey, String rfcEmisor, String uuid) {
      return CompletableFuture.supplyAsync(() -> {
          try {
              ServicioTimbradoWS service = new ServicioTimbradoWS();
              ServicioTimbradoWSPortType port = service.getServicioTimbradoWSPort();
              
              Respuesta response = port.cancelarSP(apiKey, rfcEmisor, uuid);

              RespuestaCancelar resultado = new RespuestaCancelar();
              resultado.setCode(response.getCode());
              resultado.setMessage(response.getMessage());
              resultado.setData(response.getData());
              resultado.setStatus(response.getStatus());
              return resultado;

          } catch (Exception ex) {
              throw new RuntimeException("Error al cancelar CFDI de Sector Primario", ex);
          }
      }, executor);
  }

  // Ejemplo de uso
  public static void main(String[] args) {
      CancelarSPService service = new CancelarSPService();
      String apiKey = "TU_API_KEY_AQUI";
      String rfcEmisor = "ABC010101XYZ";
      String uuid = "C3D4E08E-12F3-4B0C-8A4D-78E6B8E47113";

      service.cancelarSPAsync(apiKey, rfcEmisor, uuid)
          .whenComplete((resultado, ex) -> {
              if (ex != null) {
                  System.err.println("Error: " + ex.getMessage());
              } else if ("success".equals(resultado.getStatus())) {
                  System.out.println("¡Cancelación de CFDI SP Exitosa!");
                  System.out.println("Acuse: " + resultado.getData());
              } else {
                  System.err.println("Error: " + resultado.getCode() + " - " + resultado.getMessage());
              }
              service.shutdown();
          }).join();
  }
}

Herramienta Zeep

Para interactuar con servicios SOAP en Python, la librería zeep es una excelente opción. Proporciona una interfaz limpia y moderna.

Instala la librería usando pip:

pip install zeep

Implementación

El siguiente código muestra una implementación robusta utilizando zeep y asyncio para realizar llamadas asíncronas al servicio web.

import asyncio
from zeep.asyncio import AsyncClient

class CancelarSPService:
    def __init__(self, wsdl_url: str):
        self.wsdl_url = wsdl_url
        self.async_client = AsyncClient(self.wsdl_url)

    async def cancelar_sp_async(self, **kwargs) -> dict:
        response = await self.async_client.service.cancelarSP(**kwargs)
        return response

async def main():
    service = CancelarSPService("https://dev.facturaloplus.com/ws/servicio.do?wsdl")
    
    params = {
        "apikey": "TU_API_KEY_AQUI",
        "rfcEmisor": "ABC010101XYZ",
        "uuid": "C3D4E08E-12F3-4B0C-8A4D-78E6B8E47113"
    }

    resultado = await service.cancelar_sp_async(**params)

    if resultado and resultado['status'] == 'success':
        print("¡Cancelación de CFDI SP Exitosa!")
        print(f"Mensaje: {resultado['message']}")
        print(f"Acuse: {resultado['data']}")
    else:
        print(f"Error: {resultado['code']} - {resultado['message']}")

if __name__ == "__main__":
    asyncio.run(main())

Herramienta SoapClient

PHP tiene soporte nativo para SOAP a través de la extensión SOAP. Asegúrate de que la extensión php-soap esté habilitada en tu archivo php.ini.

Implementación

El siguiente código muestra una implementación orientada a objetos para consumir el servicio de timbrado.

<?php
class CancelarSPService {
    private string $wsdlUrl;

    public function __construct(string $wsdlUrl) {
        $this->wsdlUrl = $wsdlUrl;
    }

    public function cancelarSP(array $params): ?object {
        try {
            $soapClient = new SoapClient($this->wsdlUrl, ['trace' => 1, 'exceptions' => true]);
            $response = $soapClient->cancelarSP($params);
            return $response->return ?? null;
        } catch (Exception $e) {
            echo "Error: " . $e->getMessage();
            return null;
        }
    }
}

// Ejemplo de uso
$service = new CancelarSPService("https://dev.facturaloplus.com/ws/servicio.do?wsdl");

$params = [
    'apikey'      => "TU_API_KEY_AQUI",
    'rfcEmisor'   => "ABC010101XYZ",
    'uuid'        => "C3D4E08E-12F3-4B0C-8A4D-78E6B8E47113"
];

$resultado = $service->cancelarSP($params);

header('Content-Type: text/plain');
if ($resultado && $resultado->status === 'success') {
    echo "¡Cancelación de CFDI SP Exitosa!\n";
    echo "Mensaje: {$resultado->message}\n";
    echo "Acuse: {$resultado->data}\n";
} else {
    echo "Error: {$resultado->code} - {$resultado->message}\n";
}
?>

Respuesta (Response)

El campo data contendrá el acuse de cancelación del SAT.

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope ...>
   <SOAP-ENV:Body>
      <ns1:cancelarSPResponse xmlns:ns1="urn:ws_api">
         <return xsi:type="tns:RespuestaCancelar">
            <code xsi:type="xsd:string">200</code>
            <message xsi:type="xsd:string">Solicitud de cancelación recibida</message>
            <data xsi:type="xsd:string"><![CDATA[<Acuse ... />]]></data>
            <status xsi:type="xsd:string">success</status>
         </return>
      </ns1:cancelarSPResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Códigos de respuesta

Los códigos de respuesta para la cancelación de CFDI son importantes para entender el resultado de la solicitud. A continuación se detallan los códigos más comunes que puedes recibir al realizar una solicitud de cancelación a través de la API.

Código Descripción Detalle
200 UUID Cancelado exitosamente Se considera una solicitud de cancelación exitosa , sin embargo esto no asegura su cancelación
202 UUID Previamente cancelado Se considera previamente cancelado. Estatus cancelado ante el SAT
203 UUID No corresponde el RFC del emisor y de quien solicita la cancelación
205 No existe El SAT da una prórroga de 72 hrs para que el comprobante aparezca con estatus Vigente posterior al envío por parte del proovedor de Certificación de CFDI. Puede que algunos comprobantes no aparezcan al momento, es necesario esperar por lo menos 72 hrs
CA 1000 CA 1000 - El xml proporcionado está mal formado o es inválido El comprobante no corresponde a la estructura de un XML o tiene mal la estructura
CA 2000 CA 2000 - No fue posible cancelar el CFDI, en estos momentos existe una intermitencia en el servicio de cancelación del SAT, por favor inente más tarde, el error que regresa el SAT es: Adicional al mensaje se agregara el mensaje generado por el servicio SAT
CA 2100 CA 2100 - No fue posible cancelar el CFDI, por favor intentelo más tarde, si el problema persiste contacte a soporte técnico. Hubo una intermitencia con el servicio del SAT y/o servicio, por favor intentelo más tarde.
CA 3000 CA 2300 - No fue posible cancelar el CFDI, por favor intentelo más tarde, si el problema persiste contacte a soporte técnico
CA203 CA203 - El UUID tiene un fallo correspondiente al emisor Acuse con error en Folio 203
CA204 CA204 - El SAT no ve que el UUID sea aplicable para cancelación
CA205 CA205 - El UUID no existe Acuse con error en folio 205
CA300 CA300 - La autenticación es incorrecta El comprobante está mal formado, verifique los esquemas del comprobante
CA301 CA301 - El XML está mal formado o es incorrecto El comprobante está mal formado, verifique los esquemas del comprobante
CA302 CA302 - Sello mal formado o inválido El sello no es válido o fue alterado
CA303 CA303 - Sello no corresponde a emisor o caduco El sello no fue generado con el certificado del emisor del comprobante
CA304 CA304 - Certificado revocado o caduco El certificado con el que se emitió el comprobante fue revocado o se encuentra caduco
CA305 CA305 - La fecha de emisión no está dentro de la vigencia del CSD del Emisor La fecha de emisión del comprobante no se encuentra dentro de la vigencia del certificado con cual fue sellado
CA306 CA306 - El certificado no es de tipo CSD Los comprobantes únicamente se pueden emitir y timbrar usando CSD
CA307 CA307 - El CFDI contiene un timbre previo El comprobante ya cuenta con un complemento TFD
CA308 CA308 - Certificado no expedido por el SAT El certificado que se utiliza para timbrar no fue generado por el SAT
CA309 CA309 - No existe cancelación que corresponda con el ID proporcionado
CASD CASD - Acuse sin descripción específica
CACFDI33 CACFDI33 - Problemas con los campos El error puede ser generado por varias opciones: Se está usando un Certificado FIEL en lugar de CSD, No se están enviando todos los campos necesarios.
300 API KEY Inválida o inexistente