Hola, he creado una funcion que consulta los registros de facturacion, antes de enviarlos a la AEAT, devuelve cualquier error que haya en ellos.
Esoy haciendo uso del servicio creado para verificar los no verificables antes de almacenarlos que han abilitado la AEAT,
aqui la descripcion.
Hay que importar la clase que define la respuesta del registro, simplemente eliminando la extension .txt
Código:
/// <summary>
/// checa la estructura del registro de alta
/// </summary>
/// <param name="alta"> Es el registro a comprobar , usa tambien Program.certificado, Program.passcertificado Son el certificado y su pasword para realizar el envio</param>
/// <param name="vervose"> por defecto true, muestra inmediatamente el mensaje de error en un message box </param>
/// <returns>Devuelve true si ha ocurrido un error, tambien devuelve en un string Program.RespuestaServidor la respuesta formateada y en Program.devuelto un objeto RespuestaValContenidoFactuSistemaFacturacionType.</returns>
public bool checaRegistro(RegistroFacturaType alta)
{
//Primero deserializamos el registro de facturacion.
string facXml = "";
try
{
XmlSerializer serializaFactura = new XmlSerializer(typeof(RegistroFacturaType));
using (var xmlw = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.UTF8;
using (XmlWriter writter = XmlWriter.Create(xmlw, settings))
{
serializaFactura.Serialize(writter, alta);
facXml = xmlw.ToString();
}
}
}
catch
{ return true; }//fallamos al deserializar}
//Eliminamos lo no necesario, solo debemos enviar el registro de alta.
facXml = facXml.Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "");
facXml = facXml.Replace("<RegistroFacturaType xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">", "");//Eliminamos la seccion
facXml = facXml.Replace("</RegistroFacturaType>", "");
//Creamos el XML Document Necesario para el envio asignandole el registro a enviar.
XmlDocument doc = new XmlDocument();
doc.LoadXml(facXml.Replace("utf-16", "utf-8"));
string responseFromServer;
//Intentamos enviar a la web
try
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/ValRegistroNoVerifactu");//Asignamos la direccion de validacion
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
//Cargamos el certificado para identificarnos en la aeat, verificando si es valido o esta caducado.
X509Certificate2 certificate = new X509Certificate2(Program.certificado, Program.passcertificado); //requiere estas variables globales que contienen el certificado y su clave
var tiempo = certificate.SubjectName;
//Verificamos que no este anulado o erroneo.
if (certificate == null)
throw new ArgumentNullException(
"El Certificado es Nulo. O el numero de serie en la configuracion es erroneo.");
//verificamos que no este caducado.
if (certificate.NotAfter < DateTime.Now)
throw new ArgumentNullException(
$"El Certificado esta caducado. NotAfter: {certificate.NotAfter}.");
//Asignamos el Certificado.
webRequest.ClientCertificates.Add(certificate);
//Abrimos un stream a la direccion, para enviar el documento.
using (Stream stream = webRequest.GetRequestStream())
{
doc.Save(stream);
}
//Escuchamos la respuesta del servidor.
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
string statusDescription = response.StatusDescription;
//leemos la respuesta a un stream
Stream dataStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataStream))
{
responseFromServer = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
}
}
catch(Exception ex1) { return true; }// Fallo la conexion por algun motivo
//Personalmente me gusta en formato indentado ai que lo modifico.
XDocument Xdoc = XDocument.Parse(responseFromServer);
Program.RespuestaServidor = Xdoc.ToString();// variable global en la que cargo la respuesta formateada para mostrar al usuario.
//Finalmente intentamos crear el registro con el XML devuelto.
XmlSerializer SerializaFactura = new XmlSerializer(typeof(RespuestaValContenidoFactuSistemaFacturacionType));
try
{
//usamos un string reader para cargar la respuesta de internet
using (var xmlw1 = new StringReader(responseFromServer))
{
// Sertializamos
using (XmlReader reader = XmlReader.Create(xmlw1))
{
Program.devuelto = SerializaFactura.Deserialize(reader) as RespuestaValContenidoFactuSistemaFacturacionType;// variable global en la que cargo el objeto completo de la respuesta
}
}
}
catch(Exception Ex2) { return true; }//Fallamos al Serializar la respuesta
try
{
RespuestaRegType reg = (RespuestaRegType)Program.devuelto.Item;
if (reg.EstadoRegistro.ToString() != "Correcto")
{
if(vervose)
MessageBox.Show(reg.DescripcionErrorRegistro, "Error: " + reg.CodigoErrorRegistro);
return true;
}
}
catch
{
MessageBox.Show((string)Program.devuelto.Item);
return true;
}
return false;
}
Funciona perfecto, incluso verifica si te pasas de los 3000 en una F2.
Cita:
<tikR:RespuestaValContenidoFactuSistemaFacturacion xmlns:tikR="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/RespuestaValRegistNoVeriFactu.xsd" xmlns:tik="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd">
<tikR:RespuestaValidacion>
<tikR:IDFactura>
<tik:IDEmisorFactura>NIF</tik:IDEmisorFactura>
<tik:NumSerieFactura>VC1-25-100009</tik:NumSerieFactura>
<tik:FechaExpedicionFactura>25-04-2025</tik:FechaExpedicionFactura>
</tikR:IDFactura>
<tikR:Operacion>
<tik:TipoOperacion>Alta</tik:TipoOperacion>
</tikR:Operacion>
<tikR:EstadoRegistro>Incorrecto</tikR:EstadoRegistro>
<tikR:CodigoErrorRegistro>1150</tikR:CodigoErrorRegistro>
<tikR: DescripcionErrorRegistro>Cuando TipoFactura sea F2 y no este informado NumRegistroAcuerdoFacturacion o FacturaSinIdentifDestinatarioArt61d no sea S el sumatorio de BaseImponibleOimporteNoSujeto y CuotaRepercutida de todas las líneas de detalle no podrá ser superior a 3.000.</tikR: DescripcionErrorRegistro>
</tikR:RespuestaValidacion>
</tikR:RespuestaValContenidoFactuSistemaFacturacion>
|
La funcion devuelve true si se encuentra un error, entonces es cuando analizamos o el string o el objeto para saber que sucedio, si ponemos a true la opcin vervose, muestra el error en pantalla inmediatamente.

Otra prueba.
Cita:
<tikR:RespuestaValContenidoFactuSistemaFacturacion xmlns:tikR="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/RespuestaValRegistNoVeriFactu.xsd" xmlns:tik="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd">
<tikR:RespuestaValidacion>
<tikR:IDFactura>
<tik:IDEmisorFactura>NIF</tik:IDEmisorFactura>
<tik:NumSerieFactura>VC1-25-100009</tik:NumSerieFactura>
<tik:FechaExpedicionFactura>25-04-2026</tik:FechaExpedicionFactura>
</tikR:IDFactura>
<tikR:Operacion>
<tik:TipoOperacion>Alta</tik:TipoOperacion>
</tikR:Operacion>
<tikR:EstadoRegistro>Incorrecto</tikR:EstadoRegistro>
<tikR:CodigoErrorRegistro>1112</tikR:CodigoErrorRegistro>
<tikR: DescripcionErrorRegistro>El campo FechaExpedicionFactura es superior a la fecha actual.</tikR: DescripcionErrorRegistro>
</tikR:RespuestaValidacion>
</tikR:RespuestaValContenidoFactuSistemaFacturacion>
|
Si os interesa estoy creando uno igual para los registros de anulacion.