Introducción

El Web Service de INSIGNA es un servicio basado en SOAP que le permitirá timbrar, cancelar y validar facturas electrónicas vía internet desde su sistema corporativo. El servicio es gratuito y fácil de implementar.

Tipos de CFDI

En el protocolo INSIGNA se identifica como un CFDI a los siguientes tipos de comprobantes:

  • Comprobante Fiscal Digital por Internet (CFDI V3.2 y CFDI V3.3)
  • Documento Electrónico de Retenciones e información de Pagos (Retención Pago V1.0)

Por lo que al hacer referencia a un CFDI dentro de este manual tomaremos en cuenta los comprobantes previamente mencionados.

Funcionalidad del Web Service

A continuación se describen las funciones del Web Service de Insigna:

Servicio Método Descripción
Timbrado de CFDI signCFDI Valida, sella (de ser requerido) y timbra un CFDI
Verificación de Timbrado verifyOperation Consulta el estatus final de una petición de timbrado mediante el Web Service
Cancelación de CFDI cancelCFDI Cancela un CFDI timbrado por previamente
Validación de CFDI validateCFDI Verifica la validez de un CFDI timbrado previamente
Consulta de CFDI getCfdiInfo Consulta el estatus actual de un CFDI timbrado o importado en el sistema de INSIGNA

Autenticación

Para conectarse al Web Service de INSIGNA es necesario proporcionar el usuario y contraseña que utiliza para ingresar a INSIGNA. La autenticación se realiza mediante el uso de un “WSSecurityHeader”, el cual incluye un “UsernameToken” con los datos de autenticación del usuario.

<soap:Header xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
		<wsse:UsernameToken>
			<wsse:Username>demowebservice</wsse:Username>
			<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Pruebas#c3rtipas</wsse:Password>
		</wsse:UsernameToken>
	</wsse:Security>
</soap:Header>
		

Figura 1 - Ejemplo de WSSecurityHeader de una petición SOAP

Respuestas con mensajes de error

En algunas situaciones, el WebService de INSIGNA puede regresar una respuesta que describe excepciones en la comunicacion con el cliente. Este tipo de respuesta está formada por un objeto OperationFailed. Los atributos del objeto OperationFailed se describen a continuación:

Párametro Tipo Descripción
errorCode int Código de error
errorDescription String Descripción del error
serverTransactionId String Identificador de la transacción proporcionado por el servidor de la aplicación
transactionId String Identificador de la transacción ingresado por el usuario
requestDate Date Fecha de petición al servidor
responseDate Date Fecha de respuesta del servidor
executionTime Long Tiempo de ejecución del comando (en milisegundos)

Estructura de una excepción

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<soap:Body>
		<soap:Fault>
			<soap:Code>
			</soap:Code>
			<soap:Reason>
			</soap:Reason>
			  <soap:Detail>
			    <OperationFailed xmlns ="http://ws.certipass.mx/">
			      <errorCode></errorCode>
			      <errorDescription></errorDescription>
			      <transactionId></transactionId>
			      <requestDate></requestDate>
			      <responseDate></responseDate>
			      <executionTime></executionTime>
			    </OperationFailed>  
			   </soap:Detail> 
		<soap:Fault>
	</soap:Body>
</soap:Envelope>
		

Figura 2 - Ejemplo de la estructura de una excepción



Timbrado de CFDI

El método signCfdi se usa para timbrar un CFDI. Si la factura no cuenta con el sello, el servicio se encargará de generarlo.

Importante

1. Si desea que el Web Service genere el sello de la factura, antes deberá registrar el RFC emisor en https://www.insigna.mx/

2. El sistema le solicitará su llave privada, el certificado (archivos .key y .cer) y la contraseña de la llave privada.

3. Si enviará los XML con el sello, no es necesario registrar el RFC en INSIGNA.

Datos de entrada

Los atributos del objeto de entrada CfdiSignWrapper son los siguientes:

Parámetro Tipo Requerido Descripción
cfdi String Requerido XML del CFDI, codificado en Base64
transactionId String Opcional Identificador de la transacción de timbrado

Estructura de petición SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"    xmlns:ws="http://ws.certipass.mx/">
	<soap:Header>
		<wsse:Security soap:mustUnderstand="true"
		xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
		xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<wsse:UsernameToken>
				<wsse:Username></wsse:Username>
			    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></wsse:Password>
			    <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"></wsse:Nonce>
			    <wsu:Created></wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap:Header>
	<soap:Body>
		<ws:signCfdi>
			<ws:cfdiSignWrapper>
				<ws:cfdi></ws:cfdi>
				<ws:transactionId></ws:transactionId>
			</ws:cfdiSignWrapper>
		</ws:signCfdi>
	</soap:Body>
</soap:Envelope>
			

Figura 3 - Estructura de petición SOAP Servicio de timbrado

Datos de respuesta

Los atributos del objeto de respuesta SignCfdiResponse son los siguientes:

Nombre de la propiedad Tipo Descripción
responseCode int Código de respuesta del timbrado
responseDescription String Descripción de la respuesta
serverTransactionId String Identificador de la transacción proporcionado por el servidor de la aplicación
transactionId String Identificador de la transacción ingresada por el usuario
requestDate Date Fecha de petición al servidor
responseDate Date Fecha de respuesta del servidor
executionTime long Tiempo de ejecución del comando (en milisegundos)
signedXml String XML del CFDI timbrado, codificado en Base64
uuid String Folio fiscal de CFDI

Estructura de respuesta SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<soap:Body>
		<signCfdiResponse xmlns=“http://ws.certipass.mx/”>
			<return>
				<responseCode></responseCode>
				<responseDescription></responseDescription>
				<transactionId></ transactionId>
				<serverTransactionId></ serverTransactionId>
				<requestDate></ requestDate>
				<responseDate></ responseDate>
				<executionTime></ executionTime>	
				<signedXml></signedXml>
				<uuid></uuid>
			</return>
		</signCfdiResponse>
	</soap:Body>
</soap:Envelope>		
			

Figura 4 - Estructura de respuesta SOAP Servicio de timbrado

Códigos de respuesta

A continuación se mencionan los posibles códigos de respuesta del comando signCfdi. Si requiere más información, favor de consultar la sección de códigos de respuesta.

Códigos de éxito

A continuación se enlistan los códigos de éxito para el comando signCfdi:

Códigos de error

A continuación se enlistan los códigos de error para el comando signCfdi:

Verificación de Timbrado

Bajo algunas circunstancias (fallos de red, timeouts, etc), es posible que no reciba la respuesta del comando de timbrado. El método verifyOperation le permite recuperar un CFDI mediante su cadena original o el identificador de transacción de timbrado.

Datos de entrada

Los atributos del objeto de entrada VerifyOperationWrapper son los siguientes:

Parámetro Tipo Requerido Descripción Observaciones
transactionId String Opcional Identificador de la transacción ingresada por el usuario
signTransactionId String Opcional Identificador utilizado en la transacción de timbrado a verificar Es requerido si no se incluye el atributo originalChain
originalChain String Opcional Cadena original del CFDI, codificada en Base64 Es requerido si no se incluye el atributo signTransactionId

Estructura de petición SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"    xmlns:ws="http://ws.certipass.mx/">
	<soap:Header>
		<wsse:Security soap:mustUnderstand="true"
		xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
		xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<wsse:UsernameToken>
				<wsse:Username></wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></wsse:Password>
				<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"></wsse:Nonce>
			    <wsu:Created></wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap:Header>
	<soap:Body>
		<ws:verifyOperation>
			<ws:verifyOperationWrapper>
				<ws:originalChain></ws:originalChain>
				<ws:signTransactionId></ws:signTransactionId>
				<ws:transactionId></ws:transactionId>
			</ws:verifyOperationWrapper>
		</ws:verifyOperation>
	</soap:Body>
</soap:Envelope>
			

Figura 5 - Estructura de petición SOAP Servicio de Verificación

Datos de respuesta

Los atributos del objeto de respuesta VerifyOperationResponse son los siguientes:

Parámetro Tipo Descripción
responseCode int Código de respuesta de la verificación
responseDescription String Descripción de la respuesta
serverTransactionId String Identificador de la transacción proporcionado por el servidor de la aplicación
transactionId String Identificador de la transacción ingresada por el usuario
requestDate Date Fecha de petición al servidor
responseDate Date Fecha de respuesta del servidor
executionTime long Tiempo de ejecución del comando (en milisegundos)
cfdi String XML del CFDI consultado, codificado en Base64
uuid String Folio fiscal de CFDI
cfdiStatus String Estatus del CFDI

Estructura de respuesta SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<soap:Body>
		<VerifyOperationResponse xmlns=“http://ws.certipass.mx/”>
			<return>
				<responseCode></responseCode>
				<responseDescription></responseDescription>
				<transactionId></ transactionId>
				<serverTransactionId></ serverTransactionId>
				<requestDate></ requestDate>
				<responseDate></ responseDate>
				<executionTime></ executionTime>	
				<cfdi></cfdi>
				<uuid></uuid>
				<cfdiStatus></cfdiStatus>
			</return>
		</VerifyOperationResponse>
	</soap:Body>
</soap:Envelope>			
			

Figura 6 - Estructura de respuesta SOAP Servicio de Verificación

Códigos de respuesta

A continuación se mencionan los posibles códigos de respuesta del comando verifyOperation. Si requiere más información, favor de consultar la sección de códigos de respuesta.

Códigos de éxito

A continuación se enlistan los códigos de éxito para el comando verifyOperation:

Códigos de error

A continuación se enlistan los códigos de error para el comando verifyOperation:

Cancelación de CFDI

El método cancelCfdi se usa para cancelar un CFDI timbrado previamente.

Importante

1. Si desea que el Web Service genere el signatureValue, antes deberá registrar el RFC emisor en https://www.insigna.mx/

2. El sistema le solicitará su llave privada, el certificado (archivos .key y .cer) y la contraseña de la llave privada.

3. Si su sistema calculará y enviará el signatureValue, no es necesario registrar el RFC en INSIGNA para cancelar sus facturas.

Aviso

Ya es posible cancelar CFDIs que no fueron timbrados por medio de INSIGNA, para ello es necesario enviar el certificado del RFC emisor como se muestra en la siguiente sección. Los CFDIs externos que se cancelan consumen un timbre.

Datos de entrada

Los atributos del objeto de entrada CfdiCancelWrapper son los siguientes:

Parámetro Tipo Requerido Descripción
uuid String Requerido Folio fiscal del CFDI previamente timbrado
cancelationDate Date Requerido Fecha de cancelación del CFDI
signatureValue String Opcional Firma requerida para cancelar el CFDI codificada en Base64; se obtiene con el RFC del emisor, el UUID del CFDI, la fecha de cancelación, el certificado y la llave privada del emisor
transactionId String Opcional Identificador de la transacción ingresada por el usuario
certificate String Opcional Atributo requerido solo si se quiere cancelar un CFDI que no fue timbrado por medio de INSIGNA, el certificado debe venir codificado en Base64. Aún cuando el certificado se encuentre registrado en https://www.insigna.mx/ es necesario enviarlo

Estructura de petición SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/">
	<soap:Header>
		<wsse:Security soap:mustUnderstand="true"
		xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
		xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<wsse:UsernameToken>
				<wsse:Username></wsse:Username>
			    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></wsse:Password>
			    <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"></wsse:Nonce>
			    <wsu:Created></wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap:Header>
	<soap:Body>
		<ws:cancelCfdi>
			<ws:cfdiCancelWrapper>
				<ws:uuid></ws:uuid>
				<ws:signatureValue></ws:signatureValue>
				<ws:cancelationDate></ws:cancelationDate>
				<ws:certificate></ws:certificate>
				<ws:transactionId></ws:transactionId>
			</ws:cfdiCancelWrapper>
		</ws:cancelCfdi>
	</soap:Body>
</soap:Envelope>
			

Figura 7 - Estructura de petición SOAP Servicio de cancelación

Datos de respuesta

Los atributos del objeto de salida CancelCfdiResponse son los siguientes:

Parámetro Tipo Descripción
responseCode int Código de respuesta de la cancelación
responseDescription String Descripción de la respuesta
serverTransactionId String Identificador de la transacción proporcionado por el servidor de la aplicación
transactionId String Identificador de la transacción ingresada por el usuario
requestDate Date Fecha de petición al servidor
responseDate Date Fecha de respuesta del servidor
executionTime long Tiempo de ejecución del comando (en milisegundos)
receipt String Acuse de cancelación del SAT, codificado en Base64

Estructura de respuesta SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<soap:Body>
		<CancelCfdiResponse xmlns=“http://ws.certipass.mx/”>
			<return>
				<responseCode></responseCode>
				<responseDescription></responseDescription>
				<transactionId></ transactionId>
				<serverTransactionId></ serverTransactionId>
				<requestDate></ requestDate>
				<responseDate></ responseDate>
				<executionTime></ executionTime>	
				<receipt></receipt>
			</return>
		</CancelCfdiResponse>
	</soap:Body>	
</soap:Envelope>			
			

Figura 8 - Estructura de respuesta SOAP Servicio de cancelación

Códigos de respuesta

A continuación se mencionan los posibles códigos de respuesta del comando cancelCfdi. Si requiere más información, favor de consultar la sección de códigos de respuesta.

Códigos de éxito

A continuación se enlistan los códigos de éxito para el comando cancelCfdi:

Códigos de error

A continuación se enlistan los códigos de error para el comando cancelCfdi:

Validación de CFDI

El método validateCfdi se usa para verificar la validez de un CFDI timbrado, incluso si no fue timbrado por medio de INSIGNA. La validación de CFDI consume un timbre.

Datos de entrada

Los atributos del objeto de entrada ValidateCfdiWrapper son los siguientes:

Parámetro Tipo Requerido Descripción
cfdi String Requerido XML del CFDI a validar, codificado en Base64
transactionId String Opcional Identificador de transacción de la validación

Estructura de petición SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/">
	<soap:Header>
		<wsse:Security soap:mustUnderstand="true"
		xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
		xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<wsse:UsernameToken>
				<wsse:Username></wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></wsse:Password>
				<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"></wsse:Nonce>
			    <wsu:Created></wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap:Header>
	<soap:Body>
		<ws:validateCfdi>
			<ws:validateCfdiWrapper>
				<ws:cfdi></ws:cfdi>
				<ws:transactionId></ws:transactionId>
			</ws:validateCfdiWrapper>
		</ws:validateCfdi>
	</soap:Body>
</soap:Envelope>			
			

Figura 9 - Estructura de petición SOAP Servicio de validación

Datos de respuesta

Los atributos del objeto de salida ValidateCfdiResponse son los siguientes:

Parámetro Tipo Descripción
responseCode int Código de respuesta de la validación
responseDescription String Descripción de la respuesta
serverTransactionId String Identificador de la transacción proporcionado por el servidor de la aplicación
transactionId String Identificador de la transacción ingresada por el usuario
requestDate Date Fecha de petición al servidor
responseDate Date Fecha de respuesta del servidor
executionTime long Tiempo de ejecución del comando (en milisegundos)

Estructura de respuesta SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<soap:Body>
		<validateCfdiResponse xmlns=“http://ws.certipass.mx/”>
			<return>
				<responseCode></responseCode>
				<responseDescription></responseDescription>
				<transactionId></ transactionId>
				<serverTransactionId></ serverTransactionId>
				<requestDate></ requestDate>
				<responseDate></ responseDate>
				<executionTime></ executionTime>	
			</return>
		</validateCfdiResponse>
	</soap:Body>	
</soap:Envelope>
			
			

Figura 10 - Estructura de respuesta SOAP Servicio de validación

Códigos de respuesta

A continuación se mencionan los posibles códigos de respuesta del comando validateCfdi. Si requiere más información, favor de consultar la sección de códigos de respuesta.

Códigos de éxito

A continuación se enlistan los códigos de éxito para el comando validateCfdi:

Códigos de error

A continuación se enlistan los códigos de error para el comando validateCfdi:

Consulta de CFDI

El método getCfdiInfo se usa para consultar el estatus de un CFDI timbrado o importado en el sistema de INSIGNA.

Datos de entrada

Los atributos del objeto de entrada CfdiInfoWrapper son los siguientes:

Parámetro Tipo Requerido Descripción
uuid String Requerido Folio fiscal del CFDI previamente timbrado
transactionId String Opcional Identificador de la transacción ingresada por el usuario

Estructura de petición SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"    xmlns:ws="http://ws.certipass.mx/">
	<soap:Header>
		<wsse:Security soap:mustUnderstand="true"
		xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
		xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<wsse:UsernameToken>
				<wsse:Username></wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></wsse:Password>
				<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"></wsse:Nonce>
			    <wsu:Created></wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap:Header>
	<soap:Body>
		<ws:getCfdiInfo>
			<ws:cfdiInfoWrapper>
				<ws:uuid></ws:uuid>
				<ws:transactionId></ws:transactionId>
			</ws:cfdiInfoWrapper>
		</ws:getCfdiInfo>
	</soap:Body>
</soap:Envelope>			
			

Figura 11 - Estructura de petición SOAP Servicio de Consulta

Datos de respuesta

Los atributos del objeto de respuesta GetCfdiInfoResponse son los siguientes:

Parámetro Tipo Descripción
responseCode int Código de respuesta de la consulta
responseDescription String Descripción de la respuesta
serverTransactionId String Identificador de la transacción proporcionado por el servidor de la aplicación
transactionId String Identificador de la transacción ingresada por el usuario
requestDate Date Fecha de petición al servidor
responseDate Date Fecha de respuesta del servidor
executionTime long Tiempo de ejecución del comando (en milisegundos)
cfdi String XML del CFDI consultado, codificado en Base64
uuid String Folio fiscal de CFDI
cfdiStatus String Estatus del CFDI

Estructura de respuesta SOAP

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	<soap:Body>
		<getCfdiInfoResponse xmlns=“http://ws.certipass.mx/”>
			<return>
				<responseCode></responseCode>
				<responseDescription></responseDescription>
				<transactionId></ transactionId>
				<serverTransactionId></ serverTransactionId>
				<requestDate></ requestDate>
				<responseDate></ responseDate>
				<executionTime></ executionTime>	
				<uuid></uuid>
				<cfdiStatus></cfdiStatus>
				<cfdi></cfdi>
			</return>
		</getCfdiInfoResponse>
	</soap:Body>	
</soap:Envelope>			
			

Figura 12 - Estructura de respuesta SOAP Servicio de Consulta

Códigos de respuesta

A continuación se mencionan los posibles códigos de respuesta del comando getCfdiInfo. Si requiere más información, favor de consultar la sección de códigos de respuesta.

Códigos de éxito

A continuación se enlistan los códigos de éxito para el comando getCfdiInfo:

Códigos de error

A continuación se enlistan los códigos de error para el comando getCfdiInfo:

Códigos de respuesta

Códigos de respuesta definidos por el SAT

Código Mensaje Descripción
201 UUID Cancelado exitosamente Cuando se puede cancelar correctamente un CFDI V3.2 o CFDI V3.3 con el UUID ingresado.
202 UUID Previamente cancelado Cuando se intenta cancelar un CFDI V3.2 o CFDI V3.3 y ya ha sido cancelado previamente.
203 UUID No corresponde el RFC del emisor y de quien solicita la cancelación Cuando se intenta cancelar un CFDI V3.2 o CFDI V3.3 y el RFC emisor es diferente al RFC que intenta cancelar.
205 UUID No existe Cuando se trata de consultar, verificar o cancelar un CFDI V3.2 o CFDI V3.3 con un UUID que no existe.
301 XML mal formado Cuando el XML del CFDI V3.2 o CFDI V3.3 no cumple con la estructura definida por el SAT.
302 Sello mal formado o inválido El sello del emisor no es válido.
303 Sello no corresponde a emisor El CSD del emisor no corresponde al RFC emisor del comprobante.
304 Certificado revocado o caduco El CSD del emisor se encuentra revocado de acuerdo a la lista LCO.
305 La fecha de emisión no está dentro de la vigencia del CSD del emisor El CSD del emisor no está vigente para la fecha de emisión del CFDI V3.2 o CFDI V3.3.
306 El certificado no es de tipo CSD El certificado no tiene la estructura de uno de tipo CSD.
307 El CFDI contiene un timbre previo El XML enviado a INSIGNA ya contiene un timbre.
308 Certificado no expedido por el SAT El CSD del emisor no fue firmado por un Certificado de Autoridad del SAT.
401 La fecha de emisión se encuentra en el futuro y fuera del rango de tolerancia (12 horas) El rango entre la fecha de emisión y la fecha actual es mayor a 12 horas.
El tiempo entra la fecha de emisión y la fecha de firmado excede el límite establecido (72 horas) El rango entre la fecha de emisión y fecha de timbrado es mayor a 72 horas.
402 RFC del emisor no se encuentra en el régimen de contribuyentes El RFC del emisor no se encuentra en la lista LCO del SAT.
403 La fecha de emisión no es posterior al 01 de enero 2012 La fecha de emisión no es posterior al 01 de enero 2012.
601 La información para buscar el comprobante no es valida Cuando se consulta una factura por medio del comando de Validación y alguno de los datos enviados no se encuentra en el SAT.
602 El comprobante no se encuentra en el sistema del SAT Cuando se consulta una factura por medio del comando de Validación y no se encuentra en el SAT.
1201 UUID Cancelado exitosamente Cuando se puede cancelar correctamente una Retención Pago V1.0 con el UUID ingresado.
1202 UUID Previamente cancelado Cuando se intenta cancelar una Retención Pago V1.0 y ya ha sido cancelado previamente.
1203 UUID no corresponde con el emisor Cuando se intenta cancelar una Retención Pago V1.0 y el RFC emisor es diferente al RFC que intenta cancelar.
1205 UUID No existe Cuando se trata de consultar, verificar o cancelar una Retención Pago V1.0 con un UUID que no existe.
1300 Autenticación no válida Cuando el token de autenticación no es válido para el servicio de cancelación.
1301 XML mal formado Cuando el XML de la Retención Pago V1.0 no cumple con la estructura definida por el SAT.
1302 Estructura de folios no válida Cuando la estructura Folio que contiene los UUID no es válida.
1303 Estructura de RFC no válida Cuando la estructura en que se presenta el RFC del emisor no es válida.
1304 Estructura de fecha no válida Cuando la estructura en que se presenta la fecha de expedición no es válida.
1305 Certificado no corresponde al emisor Cuando el Certificado del emisor de la Retención Pago V1.0 no coincide con el certificado con el cual fue firmado el CFDI.
1306 Certificado no vigente El CSD del emisor no está vigente para la fecha de emisión de la Retención Pago V1.0.
1307 Uso de FIEL no permitido Cuando se intenta cancelar una Retención Pago V1.0 utilizando una FIEL.
1308 Certificado revocado o caduco El CSD del emisor se encuentra revocado de acuerdo a la lista LCO.
1309 Firma mal formada o inválida El sello del emisor no es válido.

Códigos de respuesta definidos por el Web Service

Los siguientes códigos son definidos por INSIGNA y pertenecen exclusivamente a su protocolo de comunicación y reglas de negocio.

Código Mensaje Descripción
1000 Comando completado exitosamente Respuesta a un comando exitoso.
1002 El comprobante no se encuentra en el sistema del SAT El sistema del SAT no cuenta con el comprobante. Le sugerimos intentar más tarde.
2010 Error al validar la cantidad del parámetro Cuando las cantidades utilizadas en el CFDI no concuerdan, por ejemplo, la suma de los conceptos no es igual a la cantidad del subtotal.
2309 Timbres no disponibles Cuando el Servicio recibe un comando para timbrar pero la cuenta no tiene timbres disponibles.
2500 Comando falló, servidor cerrando conexión Cuando hubo un error inesperado del lado del servidor. En cancelaciones puede indicar fallar por parte del servicio de cancelación del SAT.
2600 Error en la estructura del comprobante Cuando el xml del CFDI está mal formado.
2601 RFC emisor no coincide con el certificado emisor Cuando el RFC del emisor del CFDI no coincide con el certificado con el cual fue firmado el CFDI.
2602 Fecha de expedición del comprobante no es válida Cuando la fecha de expedición del CFDI no es válida.
2603 Error en la validación del sello de la firma del comprobante Cuando el certificado del emisor no está en la lista del LCO. Cuando el CFDI es inválido debido a que fue modificado. Cuando hay problemas de enconding.
2604 Error en la validación del sello del timbre del comprobante Cuando el CFDI es invalido debido a que fue modificado, o no se encuentra timbrado correctamente. Cuando hay problemas de encoding.
2700 CFDI No encontrado Cuando no se encuentra el CFDI correspondiente al signTransactionId o a la cadena original ingresada.
2800 No fue posible realizar la validación del CFDI ante el SAT. Favor de intentar más tarde. Cuando ocurre un error en la conexión al servicio de validación del SAT o éste tiene una falla interna.
4100 No se encontró el certificado y la llave privada para el RFC Cuando se quiere timbrar un CFDI y no se tienen los archivos para generar el sello.
4200 Error interno al procesar el comando Cuando ocurre un error no esperado en la ejecución de un comando.
4210 El usuario o la contraseña no son válidos. Favor de verificar Cuando las credenciales que se envían para la autenticación del usuario no corresponden a algún usuario de INSIGNA.
4211 Los datos de autenticación están incompletos. Por favor, verifique el usuario y la contraseña Cuando no se envían completos los datos de autenticación del usuario.
4212 La IP ha sido bloqueada Cuando el usuario intenta autenticarse 5 o más veces sin éxito.
4213 La IP no es válida Si por alguna razón no es posible detectar su dirección IP.
4214 El usuario ha sido bloqueado Cuando el usuario intenta autenticarse 5 o más veces sin éxito.
4215 La petición SOAP contiene elementos no reconocidos Cuando la petición SOAP contiene elementos que no están definidos dentro de la estructura del Servicio web.
4216 Error en el WSHeader Cuando el usuario envía elementos no reconocidos en el header de autenticación de la petición SOAP.
4217 El estatus del usuario no permite el acceso:<Estatus> Cuando un usuario que no se encuentra en Operación intenta acceder a los servicios del Servicio Web de INSIGNA.
4218 Se ha excedido el tamaño máximo de texto Cuando el usuario intenta enviar un elemento de texto con un tamaño superior al definido como máximo en el sistema.
4219 Error en la codificación base 64 de:<elemento> Cuando el usuario envía un dato que no corresponde con una codificación en Base64.
4220 Error en la estructura de la petición SOAP Cuando la petición SOAP tiene elementos no válidos para su estructura.
4221 La fecha de cancelación debe ser posterior a la fecha de emisión del CFDI Cuando se envía una fecha de cancelación anterior a la fecha de emisión del CFDI.
4222 Archivo de certificado inválido Cuando el certificado del cliente no es válido.
4223 Archivo de llave privada inválido Cuando la llave privada no es válida.
4224 Ocurrió un error al parsear uno o más de los parámetros de la petición, favor de verificar. El valor de uno o más parámetros del comando están en un formato no válido y no pudo ser interpretado (error de conversión de tipos de datos).
4225 Se ha excedido el máximo de caracteres de la petición Cuando el tamaño de la petición SOAP (número de caracteres) supera el máximo permitido.
4230 Por favor proporciona: <valor> Cuando no se ingresa un valor requerido.
Por favor verifica la escritura de: <valor> Cuando el valor ingresado tiene errores de sintaxis.
Valor fuera de rango: <valor> Cuando el valor ingresado no está dentro del rango permitido.
Error en políticas: <valor> Cuando el valor ingresado no cumple con alguna regla de negocio.
La fecha no puede ser posterior a la actual: <valor> Cuando el valor de la fecha ingresada es anterior a la actual y es requerido que sea posterior.
La fecha no puede ser anterior a la actual: <valor> Cuando el valor de la fecha ingresada es posterior a la actual y es requerido que sea anterior.
<código de error> : <mensaje> Cuando ocurre un error específico de alguna matriz de validación publicada por el SAT (Complementos, CFDI v3.3, etc.).
4231 No se encontró una operación de timbrado con el identificador de transacción proporcionado Cuando el identificador de timbrado no has ido utilizado previamente para identificar una operación de timbrado o han transcurrido más de 72 horas desde que se utilizó.
4232 Es necesario proporcionar el certificado del RFC emisor en base 64 para poder realizar la Cancelación del CFDI externo Cuando se intenta cancelar un CFDI que no fue timbrado por INSIGNA, es necesario enviar el certificado público del RFC emisor en base 64.

Ejemplo de implementación

El propósito de esta sección es explicar el proceso de creación de clientes en diferentes lenguajes que consuman los servicios del Web Service de INSIGNA. El Web Service de INSIGNA se encuentra en la url https://ws.insigna.mx/services?wsdl, sin embargo los siguientes ejemplos de implementación se conectan a nuestro ambiente de pruebas con la url https://beta.ws.insigna.mx/services?wsdl, usando las credenciales del usuario de pruebas público

JAVA

Asunciones y dependencias

Para iniciar el desarrollo del cliente es necesario contar con:

  1. Archivo INSIGNAWS.wsdl (https://beta.ws.insigna.mx/services?wsdl)
  2. Librería Apache CXF 3.1.12 (http://cxf.apache.org/)

El código completo de este cliente se encuentra en la siguiente liga: https://github.com/cops-nic/insigna-webservice-java-client

Generación de clases del Web Service

A continuación se describe como generar las clases del Web Service de INSIGNA usando la herramienta Wsdl2Java de Apache CXF, es posible generar las clases del WSDL mediante otras herramientas como wsdl2java de Apache Axis2 o wsimport de Java. La generación de las clases se puede realizar desde línea de comandos o mediante código:

  • a) Mediante línea de comando

Ubicados en la carpeta "bin" del directorio de instalación de Apache CXF ingresamos el siguiente comando:

	  wsdl2java -d rutaDelOutput rutaDelWsdl\INSIGNAWS.wsdl
	

Ejemplo:

Figura 13 - Ejemplo de uso de comando wsdl2java

En la imagen anterior se puede apreciar que en la primera línea se accede a la ruta donde se encuentra la herramienta "wsdl2java" y en la segunda ingresamos el comando requerido, donde "X" es la ruta en donde se encuentra el archivo "INSIGNAWS.wsdl" y "X:insignaCode" es la ruta donde se creará el código.

La estructura de salida se aprecia en la siguiente imagen:

Figura 14 - Ejemplo del output del comando wsdl2java

Después de ejecutar el comando, el siguiente paso es copiar la carpeta "mx" que se creó y agregarla a la carpeta "src" del proyecto en el que se desarrollará el cliente java.

  • b) Mediante código

Importando la clase org.apache.cxf.tools.wsdlto.WSDLToJava (Contenida en la librería Apache CXF ) y ejecutando su método main:

	  WSDLToJava.main(new String[] { "-d", "rutaDelOutput", "rutaDelWsdl\INSIGNAWS.wsdl"});
	

Ejemplo:

package test;
import org.apache.cxf.tools.wsdlto.WSDLToJava;

public class CodeGenerator {

	public static void main(String args[]) {
		WSDLToJava.main(new String[] { "-d", "src", "X:/INSIGNAWS.wsdl"});
		System.out.println("finished");
	}
	
}  
	

Figura 15 - Ejemplo de uso del método "main" de la clase WSDLToJava

La estructura de salida se aprecia en la siguiente imagen:

Figura 16 - Ejemplo del output del método "main" de la clase WSDLToJava

Cliente ejemplo

En la imagen siguiente se muestra el código ejemplo de una clase que funciona como cliente del Web Service de INSIGNA:

import java.util.HashMap;
import java.util.Map;

import mx.certipass.ws.CfdiInfoResult;
import mx.certipass.ws.CfdiInfoWrapper;
import mx.certipass.ws.InsignaSOAPWS;
import mx.certipass.ws.OperationFailedException;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;

public class InsignaClient {
	public static void main(String args[]) {
		
		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setServiceClass(InsignaSOAPWS.class);
		// URL de producción: https://ws.insigna.mx/services?wsdl
		String wsURL = "https://beta.ws.insigna.mx/services?wsdl";
		factory.setAddress(wsURL);
		factory.getInInterceptors().add(new LoggingInInterceptor());
		
		Map<String, Object> outProps = new HashMap<String, Object>();
		outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
		outProps.put(WSHandlerConstants.USER, "username ");
		outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
		outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientAutenticationCallBack.class.getName());
		
		WSS4JOutInterceptor loggingOutInterceptor = new WSS4JOutInterceptor(outProps);
		factory.getOutInterceptors().add(loggingOutInterceptor);
		
		InsignaSOAPWS webService = (InsignaSOAPWS) factory.create();
		Client client = ClientProxy.getClient(webService);
		HTTPConduit conduit = (HTTPConduit) client.getConduit();
		HTTPClientPolicy policy = new HTTPClientPolicy();
		policy.setConnectionTimeout(1000000L);
		policy.setReceiveTimeout(1000000L);
		policy.setAllowChunking(false);
		conduit.setClient(policy);
		CfdiInfoWrapper wrapper = new CfdiInfoWrapper();
		wrapper.setUuid("753e9e17-39f2-44f1-91fe-c7c0bec617a0");
		wrapper.setTransactionId("CII1");
		
		try {
			CfdiInfoResult result = webService.getCfdiInfo(wrapper);
			System.out.println("Cfdi: " + result.getCfdi());
			System.out.println("Estatus: " + result.getCfdiStatus());
			System.out.println("Código de respuesta: " + result.getResponseCode());
			System.out.println("Descripción de la respuesta: " + result.getResponseDescription());
			System.out.println("Transaction ID: " + result.getTransactionId());
			System.out.println("Server transaction ID: " + result.getServerTransactionId());
			System.out.println("Fecha de consulta: " + result.getRequestDate());
			System.out.println("Fecha de respuesta: " + result.getResponseDate());
			System.out.println("Tiempo de ejecución: " + 
			result.getExecutionTime());
			
		} catch (OperationFailedException fault) {
			System.out.println("Código: " + fault.getFaultInfo().getErrorCode());
			System.out.println("Mensaje: " + fault.getFaultInfo().getErrorDescription());
		}
	}
}
	

Figura 17 - Ejemplo de clase que consume los servicios del Web Service de INSIGNA

A continuación se describe brevemente las partes que componen el código anterior.

  1. Configuración del Factory necesario para obtener la instancia del Web Service:
// Se crea el factory necesario para obtener una instancia del servicio web
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(InsignaSOAPWS.class);
// URL de produccion: https://ws.insigna.mx/services?wsdl
String wsURL = "https://beta.ws.insigna.mx/services?wsdl";
factory.setAddress(wsURL);
// Creamos un interceptor de entrada default
factory.getInInterceptors().add(new LoggingInInterceptor()); 
	

Figura 18 - Ejemplo de configuración del factory

Es importante notar que la url del web Service de INSIGNA usa el protocolo HTTPS, ya que si tratamos de conectarnos mediante un protocolo HTTP el servicio no será accedido.

IMPORTANTE: Es muy común que los sitios de Beta tengan certificados firmados por el dueño del ambiente (mientras que los sitios de Producción sí tengan certificados firmados por una Autoridad Certificadora como Verisign, GlobalSign o Symantec). Es por ello que al apuntar al ambiente Beta se requiere añadir el certificado HTTPS del Web Service a la lista de "trusted certificates" de Java (archivo %JAVA_HOME%/lib/security/cacerts).

La herramienta Keytool (de Java) cuenta con un comando para realizar este import. Ver https://goo.gl/k6eoJz

	 keytool -import -alias <alias> -keystore <cacerts_file> -trustcacerts -file <certificate_filename>
	

Dado que el certificado HTTPS de Producción del Web Service de INSIGNA sí está firmado por una autoridad certificadora, no es necesario realizar esto al apuntar a Producción.

  1. Configuración de la autenticación del usuario:

Para configurar la autenticación del usuario es necesario implementar una clase "Callback" que realizará la obtención del password del usuario necesario para autenticarse en el Web Service de INSIGNA. El código de la clase se presenta a continuación:

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import org.apache.wss4j.common.ext.WSPasswordCallback;

public class ClientAutenticationCallBack implements CallbackHandler {
	
	@Override
	public void handle(Callback[] cbArray) {
		WSPasswordCallback passwordCallback = (WSPasswordCallback) cbArray[0];
		// Password que se usa para acceder a INSIGNA
		// Reemplazar por el password del usuario de Pruebas
		passwordCallback.setPassword("password");
		
		// User que se usa para acceder a INSIGNA
		// Reemplazar por el usuario de Pruebas
		passwordCallback.setIdentifier("usuario");
	}
}
	

Figura 19 - Ejemplo de clase Callback

El siguiente paso es usar el Callback en la configuración de la autenticación:

// Configuramos un interceptor de salida usando el callback de salida que
// definimos que hará la validación de la contraseña contra el callback de
// entrada del servicio web
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
// Agregamos nuestro nombre de usuario de Certipass
outProps.put(WSHandlerConstants.USER, "userName ");
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
// Agregamos el callback que generamos para autenticar al usuario
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientAutenticationCallBack.class.getName());
WSS4JOutInterceptor loggingOutInterceptor = new WSS4JOutInterceptor(outProps);
factory.getOutInterceptors().add(loggingOutInterceptor);
	

Figura 20 - Ejemplo de configuración de la autenticación del usuario

  1. Configuración del cliente que consumirá el Web Service:
// Obtenemos la instancia del servicio web
InsignaSOAPWS webService = (InsignaSOAPWS) factory.create();
// Creamos el cliente que consumirá el webservice
Client client = ClientProxy.getClient(webService);
// Configuramos el canal por el que se conectará el cliente al servicio web
HTTPConduit conduit = (HTTPConduit) client.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
// Establecemos el tiempo máximo de conexión
policy.setConnectionTimeout(1000000L);
// Establecemos el tiempo máximo que el cliente esperará una respuesta
policy.setReceiveTimeout(1000000L);
policy.setAllowChunking(false);
conduit.setClient(policy);

	

Figura 21 - Ejemplo de configuración del cliente

Es importante establecer tiempos suficientes o considerables para permitir a la aplicación esperar por la conexión y el tiempo de respuesta de los servicios del Web Service, ya que si hay interferencias en la red podría ocasionar timeouts en la comunicación de los sistemas.

  1. Llamada a métodos del Web Service:

En este punto ya se tiene todo listo para usar los servicios del Web Service de INSIGNA. A continuación se muestra una llamada al método getCfdiInfo:

	// Una vez configurada la conexión podemos llamar a los métodos del servicio web
CfdiInfoWrapper wrapper = new CfdiInfoWrapper();
	wrapper.setUuid("753e9e17-39f2-44f1-91fe-c7c0bec617a0");
	wrapper.setTransactionId("CII1");

	try {
		CfdiInfoResult result=webService.getCfdiInfo(wrapper);
		System.out.println("Cfdi: "+result.getCfdi());
		System.out.println("Estatus: "+result.getCfdiStatus());
		System.out.println("Código de respuesta: "+result.getResponseCode());
		System.out.println("Descripción de la respuesta: "+result.getResponseDescription());
		System.out.println("Transaction ID: "+result.getTransactionId());
		System.out.println("Server transaction ID: "+result.getServerTransactionId());
		System.out.println("Fecha de consulta: "+result.getRequestDate());
		System.out.println("Fecha de respuesta: "+result.getResponseDate());
		System.out.println("Tiempo de ejecución: "+result.getExecutionTime());

	} catch (OperationFailedException fault) {
			System.out.println("Código: "+fault.getFaultInfo().getErrorCode());
			System.out.println("Mensaje: "+fault.getFaultInfo().getErrorDescription());
	}
	

Figura 22 - Ejemplo de llamada a métodos del Web Service

Al ejecutar el código anterior se obtendrá la siguiente salida:

Figura 23 -Ejemplo de salida de una ejecución exitosa


.NET

Asunciones y dependencias

El propósito de esta sección es explicar el proceso de creación de clientes .NET, usando C# y Visual Basic para consumir el Servicio Web de INSIGNA. Utilizaremos Microsoft Visual Studio Community 2017 como plataforma de desarrollo, los pasos podrían variar ligeramente para versiones inferiores.

El código completo de este cliente se encuentra en la siguiente liga: https://github.com/cops-nic/insigna-webservice-.net-client

Referencia del Web service

El primer paso para crear el cliente del servicio web es agregar la referencia del Web Service de INSIGNA al proyecto en que estará nuestro cliente.

El proceso para agregar la referencia es el siguiente:

  1. Seleccionar el proyecto al cual consumirá el servicio web :

Figura 24 - Ejemplo de agregación de referencia de un servicio web, selección del proyecto

  1. Ingresar la URL del Servicio Web de INSIGNA y especificar el namespace que queremos usar para identificar las clases que se generarán.

Figura 25 - Ejemplo de creación de referencia de un servicio web, especificación de URL del servicio

Al realizar el paso anterior, tendremos importadas las clases del Servicio Web al proyecto.

Configuración de la conexión

El siguiente paso es configurar la aplicación para que se conecte al Servicio Web. A continuación se muestra un ejemplo del archivo "app.config" configurado para realizar la conexión.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <customBinding>
        <binding name="CustomSoapBinding">
          <security includeTimestamp="false"
                    authenticationMode="UserNameOverTransport"
                    defaultAlgorithmSuite="Basic256"
                    requireDerivedKeys="false"
                    messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
          </security>
          <textMessageEncoding messageVersion="Soap12"></textMessageEncoding>
          <httpsTransport maxReceivedMessageSize="2147483647"/>
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="https://beta.ws.insigna.mx/services"
                binding="customBinding"
                bindingConfiguration="CustomSoapBinding"
                contract="InsignaWs.InsignaSOAPWS"
                name="InsignaEndpoint" />
    </client>
  </system.serviceModel>
  <startup>
  <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
</configuration>
	

Figura 26 - Ejemplo de configuración de conexión en .NET

A continuación se describen brevemente las partes que componen el código anterior:

Configuración del Binding que indicará al cliente la forma en la que se transmiten los mensajes al servidor.

<bindings>
      <customBinding>
	//Configuración recomendada del binding donde se excluye el Timestamp
        <binding name="CustomSoapBinding">
          <security includeTimestamp="false"
                    authenticationMode="UserNameOverTransport"
                    defaultAlgorithmSuite="Basic256"
                    requireDerivedKeys="false"
                    messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
          </security>
	   //messageVersion Soap12 usada por el WebService de Insigna
          <textMessageEncoding messageVersion="Soap12"> </textMessageEncoding>
          <httpsTransport maxReceivedMessageSize="2147483647"/>
        </binding>
      </customBinding>
    </bindings>

Figura 27 - Ejemplo de configuración del binding

Configuración del endpoint:

//Se configura el endpoint indicando la dirección del servicio web y se usa el binding que se definió anteriormente, así mismo indicamos el nombre del contrato -->
      <endpoint address="https://beta.ws.insigna.mx/services"
                binding="customBinding"
                bindingConfiguration="CustomSoapBinding"
                contract="InsignaWs.InsignaSOAPWS"
                name="InsignaEndpoint" />

Figura 28 - Ejemplo de configuración del endpoint

En este punto ya se tiene todo listo para usar los servicios del servicio web de INSIGNA, el siguiente paso es crear el cliente.

Cliente ejemplo en C#

A continuación se muestra el código de implementación de un cliente que consume el servicio web de INSIGNA en C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InsignaWsClient.InsignaWs;
using System.ServiceModel;
using System.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InsignaWsClient.InsignaWs;
using System.ServiceModel;
using System.Net;
using System.ServiceModel.Channels;

namespace InsignaWsClient
{
    class Program
    {
        static void Main(string[] args)
        {
            //Creamos el proxy que servirá como cliente y le especificamos el endpoint al cual debe apuntar
            InsignaSOAPWSClient clientProxy = new InsignaSOAPWSClient();
            //Se configura el usuario y contraseña del usuario de Insigna
            clientProxy.ClientCredentials.UserName.UserName = "usuario";
            clientProxy.ClientCredentials.UserName.Password = "password";
            try
            {
                //Se llama a los métodos del Servicio web mediante las clases que importamos
                cfdiInfoWrapper wrapper = new cfdiInfoWrapper();
                wrapper.uuid = "905b5fec-720e-480c-b679-61d8a3d7c71a";
                CfdiInfoResult result = clientProxy.getCfdiInfo(wrapper);
                Console.WriteLine("Response Code: {0} " + result.responseCode);
                Console.WriteLine("Response Description: {0} " + result.responseDescription);
                Console.WriteLine("Request Date {0}" + result.requestDate);
                Console.WriteLine("Response Date: {0} " + result.responseDate);
                Console.WriteLine("Server transaction ID: {0} " + result.serverTransactionId);
                Console.WriteLine("Transaction ID: {0} " + result.transactionId);
                Console.WriteLine("Execution Time: {0} " + result.executionTime);
                Console.WriteLine("CfdiStatus: {0} " + result.cfdiStatus);
                Console.WriteLine("--------------------------------------------------");
                Console.WriteLine(result.cfdiStatus);
                Console.ReadLine();
            }
            catch (FaultException<operationFailed> e)
            {
                Console.WriteLine("Código de error: " + e.Detail.errorCode);
                Console.WriteLine("Descripción del error: " + e.Detail.errorDescription);

                Console.ReadLine();
            }
            catch (FaultException e)
            {
                Console.WriteLine("Error en la petición: " + e.Message);
                Console.ReadLine();
            }
        }
    }
}

Figura 29 - Ejemplo de cliente en C#.

NOTA: Es necesario reemplazar el usuario y password con las credenciales del usuario de pruebas público para que este cliente de ejemplo funcione correctamente.

Cliente ejemplo en Visual Basic

A continuación se muestra el código de implementación de un cliente que consume el servicio web de INSIGNA en Visual Basic:

Imports System.ServiceModel

Module Module1

    Sub Main()
        System.Net.ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications
        'Creamos el proxy que servirá como cliente y le especificamos el endpoint al cual debe apuntar
        Dim clientProxy As InsignaWs.InsignaSOAPWSClient
        clientProxy = New InsignaWs.InsignaSOAPWSClient
        Dim wrapper As InsignaWs.cfdiInfoWrapper
        wrapper = New InsignaWs.cfdiInfoWrapper
        Dim result As InsignaWs.CfdiInfoResult
        result = New InsignaWs.CfdiInfoResult

        Try
            'Indicamos las credenciales con las que se idenficiará el cliente en el servicio web
            clientProxy.ClientCredentials.UserName.UserName = "usuario"
            clientProxy.ClientCredentials.UserName.Password = "password"
            'Se llama a los métodos del Servicio web mediante las clases que importamos
            wrapper.uuid = "753e9e17-39f2-44f1-91fe-c7c0bec617a0"
            result = clientProxy.getCfdiInfo(wrapper)
            Console.WriteLine("Response Code: {0} " + result.responseCode)
            Console.WriteLine("Response Description: {0} " + result.responseDescription)
            Console.WriteLine("Execution Time: {0} " + result.executionTime)
            Console.WriteLine("Request Date {0}" + result.requestDate)
            Console.WriteLine("Response Date: {0} " + result.responseDate)
            Console.WriteLine("Server transaction ID: {0} " + result.serverTransactionId)
            Console.WriteLine("Transaction ID: {0} " + result.transactionId)
            Console.WriteLine("CfdiStatus: {0} " + result.cfdiStatus)

            Console.ReadLine()
        Catch ex As FaultException(Of InsignaWs.operationFailed)
            ' Si ocurre algún error se imprime el código y la descripción
            Console.WriteLine("Código de error: " + ex.Detail.errorCode.ToString)
            Console.WriteLine("Descripción del error: " + ex.Detail.errorDescription)
            Console.ReadLine()
        End Try
    End Sub
    Public Function AcceptAllCertifications(ByVal sender As Object, ByVal certifications As System.Security.Cryptography.X509Certificates.X509Certificate,
                                            ByVal chain As System.Security.Cryptography.X509Certificates.X509Chain, ByVal sslPolicyErros As System.Net.Security.SslPolicyErrors) As Boolean
        Return True
    End Function
End Module

Figura 30 - Ejemplo de cliente en Visual Basic.

NOTA: Es necesario reemplazar el usuario y password con las credenciales del usuario de pruebas público para que este cliente de ejemplo funcione correctamente.

Al ejecutar cualquiera de los dos clientes anteriores obtendremos el siguiente resultado:

Figura 31 - Ejemplo de Output del cliente en .NET cuando se consulta un cfdi

DELPHI

Asunciones y dependencias

El propósito de esta sección es explicar el proceso de creación de un cliente Delphi usando RAD Studio 10.2 como entorno de desarrollo, el proceso puede cambiar en otras versiones.

El código completo de este cliente se encuentra en la siguiente liga: https://github.com/cops-nic/insigna-webservice-delphi-client

Unidad InsignaWS

El primer paso para crear el cliente es agregar la definición del Servicio Web de INSIGNA al proyecto en que estará nuestro cliente, es decir, crear la unidad InsignaWS

El proceso para agregar la unidad es el siguiente:

  1. Si se está usando la versión 10.2 este paso no es necesario (saltar al paso 2). En versiones previas no se permitía importar automáticamente el XSD de Insigna en el WSDL con la etiqueta import, por lo que es necesario primero descargar el WSDL desde la url https://beta.ws.insigna.mx/services?wsdl.

La estructura del wsdl se muestra en la siguiente imagen:

Se necesita reemplazar la parte del WSDL que esta delimitada por el rectángulo azul con el contenido del XSD, el cual podemos descargar desde la url que viene en el atributo schemaLocation y esta subrayada con rojo (https://beta.ws.insigna.mx/services?xsd=InsignaSOAPWSService_schema1.xsd). La estructura del WSDL modificado se muestra en la siguiente imagen:

La parte delimitada por el rectángulo azul corresponde al XSD que se incrustó manualmente dentro del WSDL, por cuestiones de tamaño de la imagen solo se muestra una parte del archivo, una vez hecho esto, se guarda el WSDL localmente y se procede a importarlo.

  1. Dentro del RAD Studio, después de crear el proyecto para el cliente, seleccionar la opción del menú "Component>Import WSDL..." (la ubicación de esta opción puede variar dependiendo de la versión usada):

Figura 32 - Ejemplo de la importación del WSDL, parte 1

  1. Ingresar la URL del Servicio Web de INSIGNA y hacer clic en "Next" dejando las opciones default del Wizard.

Figura 33 - Ejemplo de la importación del WSDL, parte 2

IMPORTANTE:Si realizó el paso 1, en la url del WSDL se tendría que buscar el que se generó manualmente, en otro caso basta con colocar la url del WSDL del Web Service de INSIGNA tal como se muestra en la imagen.

Al realizar el paso anterior se creará la unidad "services" dentro del proyecto con la definición de las clases del Servicio Web de INSIGNA:

Figura 34 - Ejemplo de la estructura del proyecto al terminar de crear la unidad services

Para fines prácticos, renombremos la unidad a "InsignaWS".

Abrimos la unidad que acabamos de renombrar y nos dirigimos hacia las ultimas líneas de esta. Ya que estemos ahí, veremos unas líneas como las siguientes:

  RemClassRegistry.RegisterXSClass(verifyOperationWrapper2, 'http://ws.certipass.mx/', 'verifyOperationWrapper2', 'verifyOperationWrapper');
  RemClassRegistry.RegisterXSClass(VerifyOperationWrapper, 'http://ws.certipass.mx/', 'VerifyOperationWrapper');
  RemClassRegistry.RegisterXSClass(operationFailed2, 'http://ws.certipass.mx/', 'operationFailed2', 'operationFailed');
  RemClassRegistry.RegisterXSClass(GenericResult, 'http://ws.certipass.mx/', 'GenericResult');
  RemClassRegistry.RegisterXSClass(OperationVerifyResult, 'http://ws.certipass.mx/', 'OperationVerifyResult');
  RemClassRegistry.RegisterXSClass(cfdiInfoWrapper2, 'http://ws.certipass.mx/', 'cfdiInfoWrapper2', 'cfdiInfoWrapper');
  RemClassRegistry.RegisterXSClass(CfdiInfoResult, 'http://ws.certipass.mx/', 'CfdiInfoResult');
  RemClassRegistry.RegisterXSClass(validateCfdiWrapper2, 'http://ws.certipass.mx/', 'validateCfdiWrapper2', 'validateCfdiWrapper');
  RemClassRegistry.RegisterXSClass(ValidateCfdiWrapper, 'http://ws.certipass.mx/', 'ValidateCfdiWrapper');
  RemClassRegistry.RegisterXSClass(cfdiCancelWrapper2, 'http://ws.certipass.mx/', 'cfdiCancelWrapper2', 'cfdiCancelWrapper');
  RemClassRegistry.RegisterXSClass(CfdiCancelResult, 'http://ws.certipass.mx/', 'CfdiCancelResult');
  RemClassRegistry.RegisterXSClass(CfdiValidateResult, 'http://ws.certipass.mx/', 'CfdiValidateResult');
  RemClassRegistry.RegisterXSClass(CfdiInfoWrapper, 'http://ws.certipass.mx/', 'CfdiInfoWrapper');
  RemClassRegistry.RegisterXSClass(OperationFailed, 'http://ws.certipass.mx/', 'OperationFailed');
  RemClassRegistry.RegisterXSClass(cfdiSignWrapper2, 'http://ws.certipass.mx/', 'cfdiSignWrapper2', 'cfdiSignWrapper');
  RemClassRegistry.RegisterXSClass(CfdiSignWrapper, 'http://ws.certipass.mx/', 'CfdiSignWrapper');
  RemClassRegistry.RegisterXSClass(CfdiSignResult, 'http://ws.certipass.mx/', 'CfdiSignResult');
  RemClassRegistry.RegisterXSClass(CfdiCancelWrapper, 'http://ws.certipass.mx/', 'CfdiCancelWrapper');

end.

En la imagen anterior, el tercer argumento del metodo RegisterXSClass tiene la primera letra en mayúscula (marcada con rojo), dicha letra se tiene que cambiar a minúscula para que las peticiones SOAP puedan funcionar de forma correcta.

Unidad WSSecurity

El siguiente paso es añadir al proyecto la unidad "WSSecurity" que contiene la estructura del header de autenticación que se usará en las peticiones del cliente:

Figura 35 - Ejemplo de como agregar una unidad al proyecto

Sobrescribimos el contenido del archivo con el siguiente código:

unit WSSecurity;

interface
uses SysUtils, InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns, XMLIntf;

const
  IS_OPTN=$0001;
  IS_ATTR=$0010;
  IS_TEXT=$0020;
  IS_REF =$0080;
  IS_QUAL=$0100;

  NS_SECEXT =
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
  NS_UTILITY =
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';

type
  tTimestampFault=(wsu_MessageExpired);

  Id = type WideString;

  Created=class(TXSDateTime)
  end;

  Expires=class(TXSDateTime)
  end;

  Timestamp=class(TRemotable)
  private
    FCreated:Created;
    FExpires:Expires;
    FId: Id;
  public
    destructor Destroy; override;
  published
    property Created:Created Index (IS_OPTN) read FCreated write FCreated;
    property Expires:Expires Index (IS_OPTN) read FExpires write FExpires;
    property Id:Id Index (IS_ATTR or IS_QUAL) read FId write FId;
  end;

  AttributedString=class(TRemotable)
  private
    FText:WideString;
    FId:Id;
    FId_Specified:boolean;
    procedure SetId(Index:Integer; const AId:Id);
    function Id_Specified(Index:Integer):boolean;
  published
    property Text:WideString Index (IS_TEXT) read FText write FText;
    property Id:Id Index (IS_ATTR or IS_OPTN or IS_QUAL) read FId write
SetId stored Id_Specified;
  end;
Nonce=class(AttributedString)
  private
    FEncodingType: WideString;
    FEncodingType_Specified:boolean;
    procedure SetEncodingType(Index:Integer; const AWideString:WideString);
    function EncodingType_Specified(Index:Integer):boolean;
  published
    property EncodingType:WideString Index (IS_ATTR or IS_OPTN) read
FEncodingType write
SetEncodingType stored EncodingType_Specified;
  end;

  Password=class(AttributedString)
  private
    FType_:WideString;
    FType__Specified:boolean;
    procedure SetType_(Index:Integer; const AWideString:WideString);
    function Type__Specified(Index:Integer):boolean;
  published
    property Type_:WideString Index (IS_ATTR or IS_OPTN) read FType_ write
SetType_ stored Type__Specified;
  end;

  UsernameToken=class(TRemotable)
  private
    FUserName:string;
    FCreated:Created;
    FPassword:Password;
    FNonce: Nonce;
    FId: Id;
  public
    destructor Destroy; override;
    function   ObjectToSOAP(RootNode, ParentNode: IXMLNode;
                            const ObjConverter: IObjConverter;
                            const NodeName, NodeNamespace, ChildNamespace:
InvString; ObjConvOpts: TObjectConvertOptions;
                            out RefID: InvString): IXMLNode; override;
    property Id:Id Index (IS_ATTR or IS_QUAL) read FId write FId;
  published
    property Username:String read FUsername write FUsername;
    property Password:Password read FPassword write FPassword;
    property Nonce: Nonce read FNonce write FNonce;
    property Created:Created index (IS_REF) read FCreated write FCreated;
  end;

  Security=class(TSOAPHeader)
  private

    FUserNameToken:UserNameToken;
  public
    destructor Destroy; override;
published

    property UsernameToken:UsernameToken index (IS_REF) read FUserNameToken
write FUserNameToken;
  end;

implementation

destructor Timestamp.Destroy;
begin
  FreeAndNIL(FCreated);
  FreeAndNIL(FExpires);
  inherited Destroy;
end;

destructor UsernameToken.Destroy;
begin
  FreeAndNil(FCreated);
  FreeAndNil(FPassword);
  FreeAndNil(FNonce);
  inherited Destroy;
end;

function UsernameToken.ObjectToSOAP(RootNode, ParentNode: IXMLNode;
  const ObjConverter: IObjConverter; const NodeName, NodeNamespace,
  ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions;
  out RefID: InvString): IXMLNode;
begin
  Result := inherited;
  if (Result < > nil) and (Length(FId) > 0) then
  begin
    Result.DeclareNamespace('wsu', NS_UTILITY);
    Result.SetAttributeNS('Id', NS_UTILITY, FId);
  end;
end;

procedure AttributedString.SetId(Index:Integer; const AId:Id);
begin
  FId:=AId;
  FId_Specified:=True;
end;

function AttributedString.Id_Specified(Index:Integer):boolean;
begin
  Result:=FId_Specified;
end;

procedure Password.SetType_(Index:Integer; const AWideString:WideString);
begin
  FType_:=AWideString;
  FType__Specified:=True;
end;

function Password.Type__Specified(Index:Integer):boolean;
begin
  Result:=FType__Specified;
end;

procedure Nonce.SetEncodingType(Index:Integer; const
AWideString:WideString);
begin
  FEncodingType:=AWideString;
  FEncodingType_Specified:=True;
end;

function Nonce.EncodingType_Specified(Index:Integer):boolean;
begin
  Result:=FEncodingType_Specified;
end;

destructor Security.Destroy;
begin

  FreeAndNIL(FUserNameToken);
  inherited Destroy;
end;

initialization
  RemClassRegistry.RegisterXSClass(Security, NS_SECEXT, 'Security');
  RemClassRegistry.RegisterXSClass(UsernameToken, NS_SECEXT,
'UsernameToken');
  RemClassRegistry.RegisterXSClass(Password, NS_SECEXT, 'Password');
  RemClassRegistry.RegisterXSInfo(TypeInfo(Nonce), NS_SECEXT, 'Nonce');
  RemClassRegistry.RegisterXSInfo(TypeInfo(tTimestampFault), NS_UTILITY,
'tTimestampFault');
  RemClassRegistry.RegisterExternalPropName(TypeInfo(tTimestampFault),
'wsu_MessageExpired', 'wsu:MessageExpired');
  RemClassRegistry.RegisterXSInfo(TypeInfo(Id), NS_UTILITY, 'Id');
  RemClassRegistry.RegisterXSClass(AttributedString, NS_SECEXT,
'AttributedString');
  RemClassRegistry.RegisterExternalPropName(TypeInfo(Password), 'Type_',
'Type');
end.

Figura 36 - Código de la unidad WSSecurity

Unidad Client

Lo siguiente es agregar una unidad llamada "Client" y sobreescribir el contenido de la misma con el código que se muestra a continuación. En esta unidad es donde se llaman los métodos del servicio web de INSIGNA:

unit Client;
 interface
 uses
  InsignaWs, xmldom,WSSecurity, Soap.InvokeRegistry,
Soap.Rio, Soap.SOAPHTTPClient,Xml.XMLIntf,Soap.XSBuiltIns;

type

  TClient=Class

  published
  const
  //Las credenciales para autenticarse en INSIGNA
  stUsername = 'usuario';
  stPassword = 'password';
  var
  stWebServiceProxy:InsignaSOAPWS;
  constructor Create();

  procedure addSecurityHeader(Service: InsignaSOAPWS);
  function cancelCfdi(transactionId:string; uuid:string; signatureValue:string; cancelationDate:TXSDateTime):CfdiCancelResult;

  end;

  implementation
  //Configuración del endpoint
  constructor TClient.Create;
  var
  stHTTPRIO1: THTTPRIO;
  begin
        stHTTPRIO1:=THTTPRIO.Create(nil);
        stHTTPRIO1.URL:='https://beta.ws.insigna.mx/services';
        stHTTPRIO1.WSDLLocation:= 'https://beta.ws.insigna.mx/services?wsdl';
        //Se obtiene la instancia del webservice
        stWebServiceProxy:=GetInsignaSOAPWS(true,stHTTPRIO1.WSDLLocation,stHTTPRIO1);
        //Se agrega el SegurityHeader
        addSecurityHeader(stWebServiceProxy);
  end;


  //Configuración del Header de seguridad
  procedure TClient.addSecurityHeader(Service: InsignaSOAPWS);
  var
    Header: Security;
    Headers: ISOAPHeaders;
  begin
    Header := Security.Create;
    Header.MustUnderstand := false;
    Header.UsernameToken := UsernameToken.Create;
    Header.UsernameToken.Id := 'UsernameToken';
    Header.UsernameToken.Username := TClient.stUsername;
    Header.UsernameToken.Password := Password.Create;
    Header.UsernameToken.Password.Type_ :='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText';
Header.UsernameToken.Password.Text := TClient.stPassword;
    Header.UsernameToken.Nonce := Nonce.Create;
    Header.UsernameToken.Nonce.EncodingType :='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary';
    Header.UsernameToken.Created := Created.Create;
    Headers := (Service as ISOAPHeaders);
    Headers.OwnsSentHeaders := True;
    Headers.Send(Header);
  end;

  // Llamada al método getCfdiCancel de Certipass web service
  function TClient.cancelCfdi(transactionId:string; uuid:string; signatureValue:string; cancelationDate:TXSDateTime):CfdiCancelResult;

  var
  stWrapper:CfdiCancelWrapper;
  begin
  stWrapper:= CfdiCancelWrapper.Create;
  stWrapper.uuid:=uuid;
  stWrapper.transactionId:= transactionId;
  stWrapper.signatureValue:= signatureValue;
  stWrapper.cancelationDate:=cancelationDate;
  Result:= stWebServiceProxy.cancelCfdi(stWrapper);
  end;
  end.

Figura 37 - Ejemplo de una unidad Cliente que hace llamadas a los métodos del Servicio web de INSIGNA

A continuación se describen brevemente las partes que componen el código anterior:

  1. Definición de la clase
type

  TClient=Class

  published
  const
  //Las credenciales para autenticarse en INSIGNA
  stUsername = 'usuario';
  stPassword = 'password';
  var
  stWebServiceProxy:InsignaSOAPWS;
  constructor Create();

  procedure addSecurityHeader(Service: InsignaSOAPWS);
  function cancelCfdi(transactionId:string; uuid:string; signatureValue:string; cancelationDate:TXSDateTime):CfdiCancelResult;

  end;

Figura 38 - Ejemplo de la sección de definición de una clase

NOTA: Es necesario reemplazar el usuario y password con las credenciales del usuario de pruebas público para que este cliente de ejemplo funcione correctamente.

  1. Implementación de los procedure y functions
implementation
  //Configuración del endpoint
  constructor TClient.Create;
  var
  stHTTPRIO1: THTTPRIO;
  begin
        stHTTPRIO1:=THTTPRIO.Create(nil);
        stHTTPRIO1.URL:='https://beta.ws.insigna.mx/services';
        stHTTPRIO1.WSDLLocation:= 'https://beta.ws.insigna.mx/services?wsdl';
        //Se obtiene la instancia del webservice
        stWebServiceProxy:=GetInsignaSOAPWS(true,stHTTPRIO1.WSDLLocation,stHTTPRIO1);
        //Se agrega el SegurityHeader
        addSecurityHeader(stWebServiceProxy);
  end;


  //Configuración del Header de seguridad
  procedure TClient.addSecurityHeader(Service: InsignaSOAPWS);
  var
    Header: Security;
    Headers: ISOAPHeaders;
  begin
    Header := Security.Create;
    Header.MustUnderstand := false;
    Header.UsernameToken := UsernameToken.Create;
    Header.UsernameToken.Id := 'UsernameToken';
    Header.UsernameToken.Username := TClient.stUsername;
    Header.UsernameToken.Password := Password.Create;
    Header.UsernameToken.Password.Type_ :='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText';
    Header.UsernameToken.Password.Text := TClient.stPassword;
    Header.UsernameToken.Nonce := Nonce.Create;
    Header.UsernameToken.Nonce.EncodingType :='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary';
    Header.UsernameToken.Created := Created.Create;
    Headers := (Service as ISOAPHeaders);
    Headers.OwnsSentHeaders := True;
    Headers.Send(Header);
  end;

  // Llamada al método getCfdiCancel de Certipass web service
  function TClient.cancelCfdi(transactionId:string; uuid:string; signatureValue:string; cancelationDate:TXSDateTime):CfdiCancelResult;

  var
  stWrapper:CfdiCancelWrapper;
  begin
stWrapper:= CfdiCancelWrapper.Create;
  stWrapper.uuid:=uuid;
  stWrapper.transactionId:= transactionId;
  stWrapper.signatureValue:= signatureValue;
  stWrapper.cancelationDate:=cancelationDate;
  Result:= stWebServiceProxy.cancelCfdi(stWrapper);
  end;
  end.

Figura 39 - Ejemplo de la sección de implementación de una clase

Cliente ejemplo

El último paso es usar las unidades que se definieron anteriormente para consumir el Servicio Web. A continuación se muestra un ejemplo de cómo realizarlo:

program InsignaClient;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Soap.XSBuiltIns,
  InsignaWS in 'InsignaWS.pas',
  WSSecurity in 'WSSecurity.pas',
  Client in 'Client.pas',
  ActiveX,
  Windows,
  InvokeRegistry;

var
  proxy : TClient;
  userExit : string; //Variable de apoyo para evitar que la consola se cierre cuando se completa el proceso
  consultResult : CfdiCancelResult;
  date : TXSDateTime;

begin
date:=TXSDateTime.Create();
       date.XSToNative('2014-12-01T00:00:00');
        CoInitialize(nil);
  //Inicialización del cliente
  proxy:=TClient.Create;
  //Inicialización del objeto que guardará la respuesta
  consultResult:=CfdiCancelResult.Create;
  WriteLn('Cliente creado');
  try
    //Llamada al método que se definio en la unidad Client
     consultResult:=proxy.cancelCfdi('', 'd170f2c1-885f-4a64-95ec-5a22e75d07a4', '', date);

     WriteLn('Código de Respuesta: '+consultResult.responseCode.ToString());
     WriteLn('Descripción de Respuesta: 
     '+consultResult.responseDescription);
     WriteLn('ID de transacción: '+consultResult.transactionId);
     WriteLn('ID de transacción en el Servidor: '+consultResult.serverTransactionId);
     WriteLn('Fecha de Solicitud: '+DateTimeToStr(consultResult.requestDate.AsDateTime));
     WriteLn('Fecha de Respuesta: '+ DateTimeToStr(consultResult.responseDate.AsDateTime));
     WriteLn('Tiempo de Ejecución: '+consultResult.executionTime.ToString());

     ReadLn(userExit);
    except
    on E: ERemotableException do
    begin
          Writeln('Error '+E.FaultDetail);
          ReadLn(userExit);
    end;
  end;
end.
     

Figura 40 - Ejemplo de cliente en Delphi

Al final la estructura del proyecto se vería como se muestra en la siguiente imagen:

Al ejecutar el proyecto obtendremos el siguiente resultado:

Figura 41 - Ejemplo de Output del cliente en Delphi, cuando se quiere cancelar un CFDI que no existe

Ya que el uuid mandado a cancelar no se encuentra en el sistema de INSIGNA, el Web Service responde con un código de error 4232 porque se interpreta como cancelación de un cfdi externo. Recibir este código de respuesta significa que el cliente creado funciona correctamente.

Python

Asunciones y dependencias

El propósito de este documento es describir el proceso de creación de un cliente usando el lenguaje Python para consumir el Servicio Web de INSIGNA. Para iniciar el desarrollo es necesario contar con:

  1. Python versión 2.6 (https://www.python.org/downloads/windows/).
  2. IDE Eclipse 4.6 (NEON).
  3. Pydev (http://www.pydev.org/manual_101_install.html), Plugin para el desarrollo de proyectos Python en Eclipse.
  4. Directorio suds (https://pypi.python.org/pypi/suds), librería de Python para el desarrollo de clientes de Web Services.

El código completo de este cliente se encuentra en la siguiente liga: https://github.com/cops-nic/insigna-webservice-python-client

Librería Suds

El primer paso para crear el cliente es hacer uso la librería "Suds". Una vez descargarda dicha librería hay que descomprimirla para obtener el directorio "suds":

Figura 42 - Ejemplo de librería "Suds" descomprimida

Lo siguiente es agregar este directorio "suds" y todo su contenido al proyecto donde estará el cliente Python:

Figura 43 - Ejemplo de la estructura del proyecto al agregar el directorio "suds" de la librería Suds

Al realizar el paso anterior ya podremos usar las clases de la librería para crear el cliente del Web Service de INSIGNA.

WsSecurity

El siguiente paso es crear la clase que realizará la autenticación del cliente al Servicio Web. A continuación se muestra un ejemplo de cómo realizarlo:

#importamos la clase Element de suds.wsse
from suds.wsse import  Element

class WsSecurityHeader(object):


    def __init__(self):
        #do nothing
        pass
        
        '''
        Método que crear el Security header necesario 
        para autenticar al cliente al Web service
        '''
    def getSecurityHeader(self,username,password): 
        #Define del namespace 
        wsns=('wsse','http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd')
        ##Crea el elemento Security
        security=Element('Security',ns=wsns)
        #Crea del usernametoken
        usernametoken=Element('UsernameToken',ns=wsns)
        username=Element('Username',ns=wsns).setText(username)
        password=Element('Password',ns=wsns).setText(password)
        password.set('Type', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText')
        #Agrega el username y el password al usernametoken
        usernametoken.insert(username)
        usernametoken.insert(password)
        #Agrega el usernametoken al Security
        security.insert(usernametoken)
        return security

Figura 44 - Código de la clase WsSecurityHeader

Cliente ejemplo

A continuación se muestra el código de implementación de un cliente que consume los métodos del Web Service de INSIGNA:

if __name__ == '__main__':
    from suds.client import Client,WebFault
    from ws.WsSecurity import WsSecurityHeader
    
    try:
        #URL del webservice
        url='https://beta.ws.insigna.mx/services?wsdl'
        #Se crea el proxy del Web service
        client=Client(url)
        #Se agrega el security header con el username y password para la autenticacion
        secureHeader=WsSecurityHeader().getSecurityHeader('usuario','password')
        client.set_options(soapheaders=secureHeader)
        #Se usan los metodos y objetos propios del Web service de INSIGNA
        wrapper=client.factory.create('cfdiInfoWrapper')
        wrapper.uuid='e08b6418-5f55-428a-b5eb-d469531ada1b'
        wrapper.transactionId='tr1'
        infoResult=client.factory.create('CfdiInfoResult')
        infoResult=client.service.getCfdiInfo(wrapper)
        print infoResult
    except WebFault as detail:
        error= detail.fault.detail.OperationFailed
        print error.errorCode+': '+error.errorDescription               
    pass

Figura 45 - Ejemplo de un Cliente que hace llamadas a los métodos del Web Service de INSIGNA

NOTA: Es necesario reemplazar el usuario y password con las credenciales del usuario de pruebas público para que este cliente de ejemplo funcione correctamente.

Al ejecutar el cliente se obtendrá algo similar al siguiente resultado:

(CfdiInfoResult){
   responseCode = 205
   responseDescription = "UUID No existe"
   transactionId = "tr1"
   serverTransactionId = "4670"
   requestDate = 2017-09-01 11:23:25
   responseDate = 2017-09-01 11:23:25.000877
   executionTime = 877
}
	

Figura 46 - Ejemplo de Output del cliente en Python, cuando se quiere consultar un CFDI no se encuentra en el sistema de Insigna

PHP

Asunciones y dependencias

El propósito de esta sección es explicar el proceso de creación de un cliente PHP para consumir el Web Service de INSIGNA. Se utilizará notepad++ como herramienta para el desarrollo, el motor de PHP versión 7.2.0 y la línea de comandos de Windows.

Antes de comenzar con el desarrollo del cliente es necesario activar las extensiones soap y openssl dentro del archivo de configuración php.ini como se muestra en la siguiente imagen (los nombres de estas extensiones pueden ser diferentes dependiendo de la versión de PHP usada):

Se recomienda que la ruta de instalación de PHP sea "C:php" ya que PHP buscará por default en la ruta "C:phpext" las extensiones antes mencionadas.

El código completo de este cliente se encuentra en la siguiente liga: https://github.com/cops-nic/insigna-webservice-php-client

Cliente ejemplo

Clase InsignaClient: A continuación se muestra el código de la clase InsignaClient que se conecta al Web Service de INSIGNA:
<?php

class InsignaClient
{
    
    protected $soapClient;
    
    protected $responseCode;
    protected $responseDescription;
    protected $transactionId;
    protected $serverTransactionId;
    protected $requestDate;
    protected $responseDate;
    protected $executionTime;


    
    private $wsseUser;
    private $wssePassword;
    
    protected $wsseHeader;
    protected $soapResult;
    //Constructor que inicializa el objeto.
    public function __construct($wsseUser, $wssePassword)
    {
        
        $this->wsseUser     = $wsseUser;
        $this->wssePassword = $wssePassword;
        $this->initializeWsse();
        $this->initializeSoapClient();
    }
    //En este método inicializamos el header para implementar wsse en 
    //el cliente.
    private function initializeWsse()
    {
       $this->wsseHeader = 
'<wsse:Security env:mustUnderstand="1"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' . ' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' . ' xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"' . ' xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> ' . ' <wsse:UsernameToken><wsse:Username>' .
$this->wsseUser .
 '</wsse:Username> ' . ' <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-' . 'wss-username-token-profile-1.0#PasswordText">' . 
$this->wssePassword . 
'</wsse:Password></wsse:UsernameToken></wsse:Security>';
        
        
        $this->wsseHeader = new SoapVar($this->wsseHeader, XSD_ANYXML);
        //En esta parte dejamos listo el SoapHeader que vamos a utilizar 
        //cada vez que hagamos un request con el cliente Soap.            
        $this->wsseHeader = new SoapHeader('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'Security', $this->wsseHeader, true);
        
        
    }
    
    //En este método inicializamos el cliente soap con sus respectivos 
    //parámetros:
    //Url del wsdl, versión de soap:1_2,
    //le especificamos que no ponga en cache el wsdl, 
    //y le indicamos que utilizará ssl como método de encryptamiento.

    private function initializeSoapClient()
    {
        $this->soapClient = new SoapClient('https://beta.ws.insigna.mx/services?wsdl', array(
            'soap_version' => SOAP_1_2,
            'cache_wsdl' => WSDL_CACHE_NONE,
            'ssl_method' => SOAP_SSL_METHOD_TLS
        ));
		
    }
    //Método que devuelve el código de respuesta.
    public function getResponseCode()
    {
        return $this->responseCode;
    }
    //Método que devuelve la descripción de la respuesta.
    public function getResponseDescription()
    {
        return $this->responseDescription;
    }
        //Método que devuelve el transaction id.
    public function getTransactionId()
    {
        return $this->transactionId;
    }
    //Método que devuelve server transaction id.
    public function getServerTransactionId()
    {
        return $this->serverTransactionId;
    }
    //Método que devuelve el requestDate.
    public function getRequestDate()
    {
        return $this->requestDate;
    }
    //Método que devuelve el responseDate.
    public function getResponseDate()
    {
        return $this->responseDate;
    }
    //Método que devuelve el executionTime.
    public function getExecutionTime()
    {
        return $this->executionTime;
    }
}
?>

Figura 50 - Ejemplo de clase base para la implementación de la funcionalidad básica del cliente soap.

Se deben crear subclases que hereden de esta clase para cada una de las funciones que ofrece el Web Service.

Clase CfdiInfoWrapper

A continuación se muestra el código de la clase CfdiInfoWrapper, la cual hereda de InsignaClient e implementa métodos y propiedades para llamar a la función cfdiInfo del Web Service.

<?php
include_once(__DIR__ . DIRECTORY_SEPARATOR . 'InsignaClient.php');

class CfdiInfoWrapper extends InsignaClient
{
    private $cfdi;
    private $uuid;
    private $cfdiStatus;
    
    public function __construct($wsseuser, $wssepassword)
    {
        //Se construye el padre de la clase(InsignaClient)
        parent::__construct($wsseuser, $wssepassword);
    }
    //En este método ingresamos los parámetros y los headers,
    //al cliente soap y llamamos a la operación del web service
    //que deseamos, que en este caso es getCfdiInfo. 
    public function getCfdiInfo($uuid, $transactionId)
    {
          try {
            
            //Arreglo que se va a utilizar para ingresar el wrapper
            //específico de esta operación(cfdiInfoWrapper), a la
            //solicitud soap.
            $param = array();
             
            //Arreglo que se va a utilizar para ingresar los
            //parámetros que se necesitan para el web service
            $parametros = array();
			
            $parametros[] = new SoapVar($uuid, XSD_STRING, null, null, 'ns1:uuid');
			$parametros[] = new SoapVar($transactionId, XSD_STRING, null, null, 'ns1:transactionId');
            $param[] = new SoapVar($parametros, SOAP_ENC_OBJECT, null, null, 'ns1:cfdiInfoWrapper');
  
            //Agregamos el header wsse el se construye en la clase
            //padre una vez que llamamos a su constructor. 
            $this->soapClient->__setSoapHeaders($this->wsseHeader);
            
            //Realizamos la llamada soap
            $this->soapResult = $this->soapClient->getCfdiInfo(new SoapVar($param, SOAP_ENC_OBJECT));

            
            //Obtenemos cada una de las propiedades de la respuesta
            //enviada por el webservice.
            $this->responseCode = $this->soapResult->return->responseCode;
            
            $this->responseDescription = $this->soapResult->return->responseDescription;
            $this->transactionId = $this->soapResult->return-> transactionId;
            $this->serverTransactionId = $this->soapResult->return-> serverTransactionId;
            $this->requestDate = $this->soapResult->return-> requestDate;
            $this->responseDate = $this->soapResult->return-> responseDate;
            $this->executionTime = $this->soapResult->return-> executionTime;
            
            $this->cfdi = isset($this->soapResult->return->cfdi)  ? 
            $this->soapResult->return->cfdi : '';
            
            $this->uuid = isset($this->soapResult->return->uuid) ?
            $this->soapResult->return->uuid : '';
            
            $this->cfdiStatus = isset($this->soapResult->return->cfdiStatus) ?
            $this->soapResult->return->cfdiStatus : '';
        }
        catch (SoapFault $e) {
            //En esta parte se manejan las excepciones mandadas por
            //el web service. 
			if(isset($e->detail->OperationFailed))
			{
				echo('Codigo de Error:' . $e->detail->OperationFailed->errorCode."\n");
				echo('Descripcion de Error:' . $e->detail->OperationFailed->errorDescription."\n");
				echo('ID de Transaccion:' . $e->detail->OperationFailed->serverTransactionId."\n");
				echo('Fecha de Solicitud:' . $e->detail->OperationFailed->requestDate."\n");
				echo('Fecha de Respuesta:' . $e->detail->OperationFailed->responseDate."\n");
				echo('Tiempo de Ejecucion:' . $e->detail->OperationFailed->executionTime."\n");
			}
			else
			{
				echo('Codigo de Error:' . $e->getCode()."\n");
				echo('Descripcion de Error:' . $e->detail->getMessage()."\n");
			}
		} 
}
    //Métodos que retornan el valor de cada uno de los parámetros.
    //de respuesta enviados por el webservice.
    public function getCfdi()
    {
        return $this->cfdi;
    }
    public function getUuid()
    {
        return $this->uuid;
    }
    public function getCfdiStatus()
    {
        return $this->cfdiStatus;
    }
}
?>

Figura 51 - Ejemplo de una subclase que hereda de la clase base InsignaClient la cual es utilizada para obtener la información de un cfdi.

Consulta de cfdi utilizando la clase CfdiInfoWrapper

A continuación se muestra un script que hace uso de la clase CfdiInfoWrapper para hacer la llamada a cfdiInfo del Web Service de INSIGNA:

<?php

include_once(__DIR__ . DIRECTORY_SEPARATOR . 'CfdiInfoWrapper.php');

//Usuario y password de autenticacion en INSIGNA
$user='usuario';
$password='password';

$uuid='e08b6418-5f55-428a-b5eb-d469531ada1b';
$transactionId='tr01';

$cfdi_info= new CfdiInfoWrapper($user,$password);
$cfdi_info->getCfdiInfo($uuid, $transactionId);
echo ($cfdi_info->getResponseCode());  
echo ("\n");
echo ($cfdi_info->getResponseDescription());
echo ("\n");
echo ($cfdi_info->getTransactionId());
echo ("\n");
echo ($cfdi_info->getServerTransactionId());
echo ("\n");
echo ($cfdi_info->getRequestDate());
echo ("\n");
echo ($cfdi_info->getResponseDate());
echo ("\n");
echo ($cfdi_info->getExecutionTime());

?>

Figura 52 - Ejemplo de script para ejecutar el cliente PHP.

NOTA: Es necesario reemplazar el usuario y password con las credenciales del usuario de pruebas público para que este cliente de ejemplo funcione correctamente.

En esta sección muestra la sintaxis para ejecutar un script PHP en línea de comandos:

Figura 53 - Ejemplo de como ejecutar un script php en la línea de comandos de Windows.

A continuación se muestra la respuesta que manda el Web Service de INSIGNA al ejecutar el script creado previamente:

Figura 54 - Datos de salida devueltos por el script ejecutado.