Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Internet (https://www.clubdelphi.com/foros/forumdisplay.php?f=3)
-   -   Ley antifraude 2021 (VERIFACTU) - Programas informáticos (https://www.clubdelphi.com/foros/showthread.php?t=95235)

ermendalenda 08-02-2024 10:28:03

Cita:

Empezado por jlmoli_67 (Mensaje 554383)
Ya lo consegui, gracias.

Tengo ya casi todo el xml. Lo poco que me queda creo que no me dara problemas.

El codigo lo desarrolle en vb .net y lo tengo bastante avanzado. Si alguien lo necesita sera un placer darselo.

Gracias jlmoli_67

ermendalenda 08-02-2024 10:33:10

Nodo [Cupon]
 
Hola, no sé si alguno ha visto el nuevo nodo en esta versión.
Cupon
Identificador que especifica si tiene minoración de la base imponible por la concesión de cupones, bonificaciones o descuentos cuando solo se expide el original de la factura. Este campo es necesario porque contribuye a completar el detalle de la tipología de la factura.
Si no se informa este campo se entenderá que tiene valor “N”.

A ver si alguno entiende la parte que he subrayado, parece que si generas copia o duplicado NO?, lo veo fatal explicado.
O sea si aplico cualquier descuento en tiquet o factura tengo que informar este campo?
Uff este campo es muy chungo.

keys 08-02-2024 10:48:36

Cita:

Empezado por ermendalenda (Mensaje 554385)
Hola, no sé si alguno ha visto el nuevo nodo en esta versión.
Cupon
Identificador que especifica si tiene minoración de la base imponible por la concesión de cupones, bonificaciones o descuentos cuando solo se expide el original de la factura. Este campo es necesario porque contribuye a completar el detalle de la tipología de la factura.
Si no se informa este campo se entenderá que tiene valor “N”.

A ver si alguno entiende la parte que he subrayado, parece que si generas copia o duplicado NO?, lo veo fatal explicado.
O sea si aplico cualquier descuento en tiquet o factura tengo que informar este campo?
Uff este campo es muy chungo.

Esto es lo que indica el SII sobre ese campo.

Cita:

3.14. ¿Cómo registra un fabricante la minoración de la base imponible del impuesto
por la concesión de cupones, bonificaciones o descuentos efectuados a los
clientes de sus distribuidores?


Se trata de supuestos en que el fabricante expide únicamente el original de la factura
rectificativa sin que resulte procedente entregar copia al distribuidor, ya que este no
debe rectificar las cuotas devengadas ni sus deducciones.

La información deberá remitirse en el bloque funcional “Desglose a nivel de factura”
marcando el campo “cupón”.
Este campo es compatible con las claves R1, R5 (factura rectificativa simplificada) y
F4 (asiento resumen facturas).


Ejemplo: si el descuento ofrecido por la entidad distribuidora a los consumidores
finales es de 121 euros y tal importe es reembolsado por el fabricante, éste reducirá la
base imponible en 100 euros (121 euros / 1,21). Consulta DGT V2966-15
Nosotros es un campo que lo tiene que marcar el usuario si lo quiere. Como ves solo se puede marcar en las rectificativas, no es para cualquier tipo de descuento.

ermendalenda 08-02-2024 11:46:55

Cita:

Empezado por keys (Mensaje 554386)
Esto es lo que indica el SII sobre ese campo.



Nosotros es un campo que lo tiene que marcar el usuario si lo quiere. Como ves solo se puede marcar en las rectificativas, no es para cualquier tipo de descuento.


Ufff, gracias, menos mal.

ermendalenda 08-02-2024 13:42:15

Chorus
 
Aunque lo he puesto en un post de la factura electronica, os dejo esto en el que se habla de verifactu y la B2B
Chorus, es lo que parece que va a ser la plataforma gratuita para cumplir con los requisitos minimos de la B2B, esperemos que sea así:
https://sede.agenciatributaria.gob.e...ta-sesion.html

jlmoli_67 11-02-2024 09:09:45

Dureccion de envio para entorno de pruebas
 
Buenos dias,


Alguien me podria decir cual es la direccion para verifactu a la cual hay que enviar el xml mediante soap al entorno de pruebas?


Es la primera vez que lo intento y tengo un lio de mil pares de narices.


Gracias

ermendalenda 11-02-2024 09:38:31

Cita:

Empezado por jlmoli_67 (Mensaje 554423)
Buenos dias,


Alguien me podria decir cual es la direccion para verifactu a la cual hay que enviar el xml mediante soap al entorno de pruebas?


Es la primera vez que lo intento y tengo un lio de mil pares de narices.


Gracias


Buenos días
Aún no existe el entorno de pruebas, hay que esperar, cuando publiquen en el BOE la Orden Ministerial se sabrá.
Dicen que en las próximas semanas (que puede ser, y ojalá sea, en los próximos meses:D)

jlmoli_67 11-02-2024 12:24:45

Muchas gracias.

Pienso que deberian de haber dejado todo preparado antes de poner el reloj de los 9 meses a contar,pero en fin,es lo que hay. Te agradezco la informacion.

Sistel 11-02-2024 12:32:08

Cita:

Empezado por jlmoli_67 (Mensaje 554425)
Pienso que deberian de haber dejado todo preparado antes de poner el reloj de los 9 meses a contar,pero en fin,es lo que hay. Te agradezco la informacion.

Hola,

El reloj de los 9 meses se activará a partir de que se publique la Orden Ministerial.

Saludos

jlmoli_67 11-02-2024 18:34:33

Estupendo. Me das una alegria

Gracias

ermendalenda 11-02-2024 20:53:17

Lógica encadenamiento por incidencias
 
Hola, aunque esperaremos a la O.M. a ver como veis la lógica por incidencias.

Ejemplo 1
Incidencia:
Genero Factura 1 Envio Factura 1 (Me devuelve que tengo que enviar minimo 2 registros o esperar minimo 15 minutos)
Genero Factura 2 Encadeno con 1
Genero Factura 3 encadeno con 2

Ocurre una incidencia, error de disco... El registro numero 2 se corrompe y tengo que regenerarlo
genero Registro 2 de nuevo encadeno con 3 y creo Nodo <Incidencia>S</Incidencia>

Genero Factura 4 encadeno con nuevo registro 2


Ejemplo 2
Incidencia:
Genero Factura 1 Envio Factura 1 (Me devuelve que tengo que enviar minimo 2 registros o esperar minimo 15 minutos)
Genero Factura 2 Encadeno con 1
Genero Factura 3 encadeno con 2

Ocurre una incidencia, error de disco... El registro numero 2 se corrompe, la Base de datos se corrompe, no puedo recuperar registro, creo un log de incidencia(Que aun no sabemos si hay que hacer con estructura si estoy en envio inmediato)
Ahora hay 2 posiblidades:
He perdido un registro de factura, que si es algo importante lo recordare y podre marcar de nuevo, la siguiente factura, al no existir datos vuelvo a generarlo como Factura Numero 2 pero con el nodo <Incidencia>S</Incidencia> por que he detectado una anomalia pero con los datos que recuerdo.
O es una factura simplificada de algo de poco importe y no recuerdo nada: la siguiente factura, al no existir datos vuelvo a generarlo como Factura Numero 2 pero con el nodo <Incidencia>S</Incidencia> por que he detectado una anomalia, PERO SE PIERDE UNA FACTURA SIMPLIFICADA.

A ver como lo veis, y que hariais.

ermendalenda 14-02-2024 10:55:12

Esta tarde zoom hacienda
 
Buenos días
No voy a poder ver el zoom, si sabéis donde ño cuelgan después o podéis hacer un r3sumen os lo agradecería
Si podéis alguno preguntar si van a ser muy estrictos con la rotura de encadenamiento para los que envian(veri*factu) es ll que más miedo me da, ya que algún error no contemplado puede provocar una rotura de encadenamiento en algún momento dado. A ver si son un poco flexibles, ya que entiendo que si estanos enviando continuamente y de vez en cuando se produce esa rotura no deberían contemplarlo como algo grave.
Saludos

newtron 14-02-2024 12:54:41

Cita:

Empezado por ermendalenda (Mensaje 554459)
Buenos días
No voy a poder ver el zoom, si sabéis donde ño cuelgan después o podéis hacer un r3sumen os lo agradecería
Si podéis alguno preguntar si van a ser muy estrictos con la rotura de encadenamiento para los que envian(veri*factu) es ll que más miedo me da, ya que algún error no contemplado puede provocar una rotura de encadenamiento en algún momento dado. A ver si son un poco flexibles, ya que entiendo que si estanos enviando continuamente y de vez en cuando se produce esa rotura no deberían contemplarlo como algo grave.
Saludos


Si son flexibles (que imagino que deben de serlo) no te lo van a decir porque podríamos pensar "ancha es Castilla". Yo intentaré estar pero todavía no lo tengo seguro.


Saludos.

ermendalenda 14-02-2024 16:36:01

Cita:

Empezado por newtron (Mensaje 554461)
Si son flexibles (que imagino que deben de serlo) no te lo van a decir porque podríamos pensar "ancha es Castilla". Yo intentaré estar pero todavía no lo tengo seguro.


Saludos.

Gracias
Otra cosa.
Ojocon los servicios de ubicación de windows para cambiar fecha y hotlra.
Menos mal que he puesto en el mismo programa la comprobación

newtron 14-02-2024 19:16:14

Buenas.


Ya ha acabado el webbinar de la aet.


Resumiendo: En principio dicen que TODO lo publicado va a cambiar, cosa que no es extraña, así que lo tengamos en cuenta. Por lo demás no han aclarado mucho más de lo que ya medio hemos comentado por aquí.



Para que todo el mundo lo tenga claro (yo ya medio lo sabía) va a haber dos tipos de SIF (programas de toda la vida), los verifactu y los que no lo son pero los dos sistemas tendrán que tener la capacidad de enviar la misma información; los verifactu en tipo real y los NO verifactu a demanda de la aeat pero con el mismo formato. A los sistemas verifactu les dará igual la huella, la firma y el registro de eventos porque se envían de forma directa y a los NO verifactu les obligarán a mantener el encadenado, registros firmados y registro de eventos.


Un tema peliagudo es que hemos preguntado varios que qué pasa si el usuario de un sistema NO verifactu consigue abrir la base de datos y modificar registros y básicamente nos amenazan con que convenzamos al cliente para que envíe y quitarnos ese marrón de encima porque no tienen claro las repercusiones que nos puede traer si eso ocurre, y lo han dicho en varias ocasiones.


Se dan un plazo de un par de meses a partir de que se publique el desarrollo de la ley para poner a disposición las urls de pruebas así que paciencia.


De momento no se me ocurre nada más que se haya comentado y que sea relevante.


Saludos.

Edito: Irán poco a poco ampliando las FAQS con todas las dudas que les van llegando.

edari 14-02-2024 19:28:29

Lo escuché yo también y destaco más o menos la pregunta de

Da la sensación de que los que envían por SII es un sistema mucho más "ligth" que las empresas que lo hagan con Verifactu que encima serán pequeñas y medianas empresas...lo cual no tiene mucho sentido...


Y han venido a contestar...


Uyyy que no es más complicado acogerse a verifactu que al SII, que con el SII tienen que además subir las compras (que es cierto)...


Mi opinión es que tienen razón los "preguntantes".....sobretodo a nivel de usuario de facturación es mucho más limitante hacerlo por Verifactu que por SII. No entiendo el motivo...


También han dicho que puede acogerse todo el mundo que quiera al SII y solucionado...que no sé yo

newtron 14-02-2024 19:42:43

Bueno... cualquiera que lo solicite puede entrar en el SII y quitarse de enmedio el rollo verifactu pero ganarás por un lado y perderás por otro por lo que no sé si merece la pena. Para mi (dependiendo también de la empresa) es más complicado el SII que el verifactu porque, como han apuntado, verifactu no entra en la naturaleza de la factura. En el SII dependiendo de la empresa se puede complicar la cosa bastante cuando entras en los distintos tipos de factura: intracomunitarias, exportación, inversión del sujeto pasivo, compras y gastos (que no existen en verifactu), etc. etc. Aparte de que las declaraciones de IVA pasan a ser mensuales que dependiendo de la empresa puede venir mejor o peor por lo que cada empresa es un mundo.


Saludos.

ermendalenda 14-02-2024 19:52:41

Gracias
Más o menos se imaginaba respecto a si quieres SIi pues ala, pero si emites toquets ya tienes que mandar sii, compras y ventas. Es diferente, tienes sus ventajas e inconvenientes.
Lo de que no haya que encadenar, pues estupendo, mucho mejor para todos. Si no van a faltar inspectores e informáticos.

keys 15-02-2024 08:39:12

Hola a todos.

Otra cosa que dijeron es que el código QR es para todas las facturas, ya sean Verifactu o no tienen que llevar el código QR. A no ser que hagas el SII.

Esta claro que si tu empresa esta en el SII te libras de todo esto. Pero eso puede ser una solución para el cliente, pero no para los que hacemos programas de facturación, ya que para que el programa sea competitivo tendrá que estar adaptado por lo menos a VERIFACTU.

Además el que una empresa haga el SII no es tan sencillo, ya que si haces el SII pasas al REDEME y por lo tanto tienes que hacer el IVA mensual y no Trimestral, registrar las compras, ciertas operaciones intracomunitarias, etc...

Una cosa que yo creo que intentaron decir es que se opte por VERIFACTU, ya que sino a parte de tener el registro de eventos, es casi imposible garantizar que no se puedan producir cambios en los registros de facturación. En el caso nuestro se trata de un programa comercial que se instala en el ordenador del cliente y por lo tanto puede entrar en cualquier momento y ponerse a borrar o restaurar ficheros, ¿y como controla eso tu programa?. Por no hablar de que puedan acceder a los ficheros y cambiar registros.

Yo creo que vamos optar por el camino de sólo VERIFACTU, ya que así es mas sencillo y la responsabilidad del programa es menor, y para los que hemos desarrollado TicketBAI no es tanto cambio. No se como no han hecho como en las forales, TODO EL MUNDO A TICKETBAI y punto.

Sistel 15-02-2024 09:00:49

Hola,

También aclararon que si se usa la opción Verifactu (opción que recomendaron encarecidamente), para el envío de las facturas se podrá emplear no sólo el certificado digital del obligado tributario sino también el de un tercero.
En este caso, el tercero deberá ser Colaborador Social y tener un documento por el que el obligado tributario le autoriza.
El modelo es éste

Saludos

Sistel 15-02-2024 09:03:17

Y aclararon que si se opta por utilizar Verifactu ya no hay obligación de firma de la factura ni de llevar el registro de eventos.
Por supuesto, sí se obliga en Verifactu a que la factura lleve un hash.

ermendalenda 15-02-2024 09:13:01

Gracias a todos los por la información
me han comentado varias cosas sobre los que van a hacer Veri*Factu(Envio):
*La Huella y el encadenamiento es necesaria, alguien ha comentado que para verifactu no lo es, pero debe estar equivocado, me han enseñado el esquema.
*La huella SHA256 en Hexadecimal y MAYÚSCULAS
*Se deben subsanar los errores (de los registros que te devuelvan con error) y volver a remitir los registros subsanados(Ya diran como, supongo que como incidencia....)

sglorka 15-02-2024 10:41:49

Resumen del Seminario
 
Hola a todos, os pongo las ideas que he sacado del seminario de ayer por si pueden ser de interés para alguno. Espero no haber cometido ningún error.

1.- Recomiendan el uso del sistema VeriFactu como opción segura para ofrecer al cliente. La opción del requerimiento tiene implicaciones que son de difícil cumplimiento y te cargan con una responsabilidad, la conservación, que es complicada de asegurar para una instalación desatendida.

2.- La imposibilidad de remitir temporalmente los registros de facturación por problemas técnicos puntuales la entienden y se abren a que utilicemos el campo Incidencia (S) de la cabecera del mensaje para notificar dicha situación. Incluso hablaron de casos en los que sólo hay Internet a ciertas horas del día y que eso es plausible.

3.- Han dejado bien claro que los sistemas VeriFactu están excluidos de la conservación, firma electrónica, accesibilidad y eventos de los registros de facturación. El evento de entrada / salida de Verifactu sólo atañe en el caso de que, NO estando en VeriFactu, (debes tener eventos) quisieras cambiarlo y entrar en Modo Verifactu, entonces deberías generar ambos eventos de salida y entrada. Ya en el nuevo modo, desaparecerían.

El modo Verifactu se resume en, envío automático, consecutivo, encadenamiento de registros y generación de huellas para cada registro de facturación. Ya para factura impresa o electrónica, adición de Qr.
Hablaron sobre el control de flujo (n,t). En principio lo van a cambiar, ya que, el número máximo de envío de registros en un mismo mensaje agrupado ya está limitado, son 1000. Por lo tanto, el parámetro “n” carece de sentido. Sí, van a utilizar el parámetro “t” en segundos.

4.- Aunque han dicho que van a mantener los servicios diferenciados para la remisión de registros a través de VeriFactu y a través de requerimiento, tiene la idea de que, dichos registros, contengan la misma información, por lo que se avecina otro cambio en la estructura del registro de alta y de anulación

5.- Piensan unificar en el mismo mensaje de envío, registros de alta y de anulación.

6.- La huella hash ya no será del nodo registro de facturación sino que se construirá con ciertos campos del xml que ya indicarán. Y lo más importante es que un error en esta huella no será considerado como motivo de rechazo sino como aceptada con errores.

7.- Dejaron entrever, que la idea final es que sólo exista un método de envío de registros de facturación a la aeat, por lo que al final, tenderemos a un híbrido entre el SII y VeriFactu como sistema de envío. Por ello, la idea de adherirse al SII para no cumplir con VeriFactu deberíamos desecharla.

8.- Los certificados electrónicos de terceros serán admisibles para remitir los registros de facturación de un obligado tributario, idéntico al SII.

pablog2k 15-02-2024 12:47:07

gran resumen, de acuerdo con lo dicho, gracias compañero ^\||/

keno_71 15-02-2024 13:07:08

Buenos días, gracias por el resumen a todos. Entonces si el sistema es Verifactu tienes que utilizar un certificado para enviar pero no para firmar la factura. El certificado tiene que estar instalado en todos los ordenadores que envíen.

ermendalenda 15-02-2024 20:03:27

Sigo pensabdo que van a mezclar verifactu con la factura electronica

ermendalenda 15-02-2024 20:03:58

Sigo pensabdo que en el xml van a mezclar verifactu con la factura electronica y Tarde o temprano meterán las líneas de los conceptos facturados.

CarlosMz 16-02-2024 08:12:01

Cita:

Empezado por sglorka (Mensaje 554477)
Hola a todos, os pongo las ideas que he sacado del seminario de ayer por si pueden ser de interés para alguno. Espero no haber cometido ningún error.

1.- Recomiendan el uso del sistema VeriFactu como opción segura para ofrecer al cliente. La opción del requerimiento tiene implicaciones que son de difícil cumplimiento y te cargan con una responsabilidad, la conservación, que es complicada de asegurar para una instalación desatendida.

2.- La imposibilidad de remitir temporalmente los registros de facturación por problemas técnicos puntuales la entienden y se abren a que utilicemos el campo Incidencia (S) de la cabecera del mensaje para notificar dicha situación. Incluso hablaron de casos en los que sólo hay Internet a ciertas horas del día y que eso es plausible.

3.- Han dejado bien claro que los sistemas VeriFactu están excluidos de la conservación, firma electrónica, accesibilidad y eventos de los registros de facturación. El evento de entrada / salida de Verifactu sólo atañe en el caso de que, NO estando en VeriFactu, (debes tener eventos) quisieras cambiarlo y entrar en Modo Verifactu, entonces deberías generar ambos eventos de salida y entrada. Ya en el nuevo modo, desaparecerían.

El modo Verifactu se resume en, envío automático, consecutivo, encadenamiento de registros y generación de huellas para cada registro de facturación. Ya para factura impresa o electrónica, adición de Qr.
Hablaron sobre el control de flujo (n,t). En principio lo van a cambiar, ya que, el número máximo de envío de registros en un mismo mensaje agrupado ya está limitado, son 1000. Por lo tanto, el parámetro “n” carece de sentido. Sí, van a utilizar el parámetro “t” en segundos.

4.- Aunque han dicho que van a mantener los servicios diferenciados para la remisión de registros a través de VeriFactu y a través de requerimiento, tiene la idea de que, dichos registros, contengan la misma información, por lo que se avecina otro cambio en la estructura del registro de alta y de anulación

5.- Piensan unificar en el mismo mensaje de envío, registros de alta y de anulación.

6.- La huella hash ya no será del nodo registro de facturación sino que se construirá con ciertos campos del xml que ya indicarán. Y lo más importante es que un error en esta huella no será considerado como motivo de rechazo sino como aceptada con errores.

7.- Dejaron entrever, que la idea final es que sólo exista un método de envío de registros de facturación a la aeat, por lo que al final, tenderemos a un híbrido entre el SII y VeriFactu como sistema de envío. Por ello, la idea de adherirse al SII para no cumplir con VeriFactu deberíamos desecharla.

8.- Los certificados electrónicos de terceros serán admisibles para remitir los registros de facturación de un obligado tributario, idéntico al SII.

Excelente resumen, muchas gracias.

Si el sistema es SOLO verifactu, no se aplica el registro de eventos en ningún caso ? Ni entrada al sistema, salida,... ?

Si el Hash se calculará sobre ciertos campos no tendremos que serializar primero el XML para obtener el nodo, entiendo ?

Neftali [Germán.Estévez] 16-02-2024 09:09:44

Algunas de las diapositivas que considero más importantes en la presentación.
Espero que aclaren las cosas junto con la explicaciones que habéis ido comentando...












Diferencias entre VERI*FACTU y no VERI*FACTU:



Neftali [Germán.Estévez] 16-02-2024 09:42:38

Y aquí adjunto algunas que son más técnicas (y porque en el mensaje anterior ya no me va a dejar añadir más... :D:D













sglorka 16-02-2024 09:59:51

Cita:

Empezado por CarlosMz (Mensaje 554501)
Excelente resumen, muchas gracias.

Si el sistema es SOLO verifactu, no se aplica el registro de eventos en ningún caso ? Ni entrada al sistema, salida,... ?

Si el Hash se calculará sobre ciertos campos no tendremos que serializar primero el XML para obtener el nodo, entiendo ?

No hay eventos en modo VeriFactu, de ningún tipo.
Como el hash se va a calcular sobre campos concretos, lo podrás obtener antes de crear el xml por lo tanto, no tienes que obtenerlo del xml generado.

Neftali [Germán.Estévez] 16-02-2024 10:00:51

Cita:

Empezado por Sistel (Mensaje 554474)
También aclararon que si se usa la opción Verifactu (opción que recomendaron encarecidamente), para el envío de las facturas se podrá emplear no sólo el certificado digital del obligado tributario sino también el de un tercero.
En este caso, el tercero deberá ser Colaborador Social y tener un documento por el que el obligado tributario le autoriza.
El modelo es éste


Añadido el documento al FTP del club y añadido enlace al mensaje #1 (recopilatorio).

CarlosMz 16-02-2024 11:13:05

Cita:

Empezado por sglorka (Mensaje 554506)
No hay eventos en modo VeriFactu, de ningún tipo.
Como el hash se va a calcular sobre campos concretos, lo podrás obtener antes de crear el xml por lo tanto, no tienes que obtenerlo del xml generado.

Se simplifica bastante, muchas gracias

ramherfer 16-02-2024 12:11:04

Una pregunta a ver si alguien me puede aclarar una duda que tengo desde hace tiempo.
¿Se deben generar los xml de cada factura por separado?
¿Luego de generados se genera el soap para enviar?
Gracias anticipadas.

ermendalenda 16-02-2024 12:23:31

Cita:

Empezado por ramherfer (Mensaje 554509)
Una pregunta a ver si alguien me puede aclarar una duda que tengo desde hace tiempo.
¿Se deben generar los xml de cada factura por separado?
¿Luego de generados se genera el soap para enviar?
Gracias anticipadas.

En el supuesto de acogerte a envio inmediato: Comp no tienes que conservarlo puedes hacerlo como quieras, pero debes tener en cuenta que te pueden contestar en el resp del soap al enviar que el próximo envío el número de xmls por ejemplo sea 10 registros encapsulados en el mismo soap o 300segunfos de espera. Entonces lo recomendable es que generes el xml por un lado y encapsules en el soap al enviar.

ramherfer 16-02-2024 12:45:55

Cita:

Empezado por ermendalenda (Mensaje 554510)
En el supuesto de acogerte a envio inmediato: Comp no tienes que conservarlo puedes hacerlo como quieras, pero debes tener en cuenta que te pueden contestar en el resp del soap al enviar que el próximo envío el número de xmls por ejemplo sea 10 registros encapsulados en el mismo soap o 300segunfos de espera. Entonces lo recomendable es que generes el xml por un lado y encapsules en el soap al enviar.

Claro, ahora comentan que la huella va calculada de datos especificos de la factura (mucho más sencillo) y antes era del nodo <RegistroFacturacion>, que esto no facilitaba las cosas, de ahí mi duda.

Vale perfecto tiene lógica, mientras encapsulas calculas la huella desde los datos de factura, no de ningún nodo. mil gracias como siempre @ermendalenda.

A ver si se aclara esta gente de una maldita vez.

ermendalenda 16-02-2024 12:56:31

Cita:

Empezado por ramherfer (Mensaje 554511)
Claro, ahora comentan que la huella va calculada de datos especificos de la factura (mucho más sencillo) y antes era del nodo <RegistroFacturacion>, que esto no facilitaba las cosas, de ahí mi duda.

Vale perfecto tiene lógica, mientras encapsulas calculas la huella desde los datos de factura, no de ningún nodo. mil gracias como siempre @ermendalenda.

A ver si se aclara esta gente de una maldita vez.

A mi me da un poco igual de donde se calcule, como genero el xml a pelo puedo elegir los nodos que quiera para calcular el hash antes de grabar el xml.
Supongo que ya cada uno tendrá sus complicaciones.
Lo que si tienes que calcular elhash antes de generar el qr de la factura, eso está claro, la explicacion de calcularla mientras encapsulas el soap antes de encapsular no es muy correcta, ya que en el qr, casi seguro va a ir parte del hash calculado, al igual que ticketbai con la firma, es la única forma que tiene para garantizar que no cambies algo entre la emisión y el envío.

ramherfer 16-02-2024 20:49:18

Cita:

Empezado por ermendalenda (Mensaje 554512)
A mi me da un poco igual de donde se calcule, como genero el xml a pelo puedo elegir los nodos que quiera para calcular el hash antes de grabar el xml.
Supongo que ya cada uno tendrá sus complicaciones.
Lo que si tienes que calcular elhash antes de generar el qr de la factura, eso está claro, la explicacion de calcularla mientras encapsulas el soap antes de encapsular no es muy correcta, ya que en el qr, casi seguro va a ir parte del hash calculado, al igual que ticketbai con la firma, es la única forma que tiene para garantizar que no cambies algo entre la emisión y el envío.

Aqui ya me he perdido.... el hash antes de generar el qr de la factura

Si que me gustaría ver un ejemplo de como encapsulas uno o varios xml generados con anterioridad. Me sería de mucha ayuda

ermendalenda 17-02-2024 10:39:09

Cita:

Empezado por ramherfer (Mensaje 554516)
Aqui ya me he perdido.... el hash antes de generar el qr de la factura

Si que me gustaría ver un ejemplo de como encapsulas uno o varios xml generados con anterioridad. Me sería de mucha ayuda

Yo te lo pongo pero no sé si te vas a liar más, ya que yo trabajo en Vb6 para generar el xml y despuñess las firmas y encapsulamientos soaps lo hago en php con llamadas desde curl.
En Delphi hay otras formas que los compañeros del foro seguro que te pueden guiar.

Mira el código para generar el XML (A pelo) es de esta forma:
Código:

close #92
Open "C:\xmls\" & nombre_fichero & ".xml" For Output  As #92
 Print #92, "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>"
              Print #92, "<?xml version=" & Chr(34) & "1.0" & Chr(34) & " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>"
                If es_anulacion Then
                   
                    Print #92, "<sum:BajaFactuSistemaFacturacion xmlns:sum=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd" & Chr(34) & " xmlns:sum1=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd" & Chr(34) & ">"
                Else
                    Print #92, "<sum:AltaFactuSistemaFacturacion xmlns:sum=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd" & Chr(34) & " xmlns:sum1=" & Chr(34) & "https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd" & Chr(34) & ">"
                End If
                Print #92, "<sum1:Cabecera>"
                Print #92, "<sum1:IDVersion>" & version_vfactu & "</sum1:IDVersion>"
 Print #92, "<sum1:ObligadoEmision>"
                Print #92, "<sum1:NombreRazon>" & TEXT_TO_UTF8(nombre_empresa) & "</sum1:NombreRazon>"
                Print #92, "<sum1:NIF>" & nif & "</sum1:NIF>"
                Print #92, "</sum1:ObligadoEmision>"
              select case tipo

                    "anulacion"
                        Print #92, "<sum1:TipoRegistroAEAT>T3</sum1:TipoRegistroAEAT>"
                   
                    "sustitutiva"
                            Print #92, "<sum1:TipoRegistroAEAT>T1</sum1:TipoRegistroAEAT>"
                    "normal"
                            Print #92, "<sum1:TipoRegistroAEAT>T0</sum1:TipoRegistroAEAT>"
              end select
***Y ahora lo que voy a escribir lo voy guardando en la variable datohash para calcular el hash cuando tenga en la variable lo que necesite
datoxml = "<sum:RegistroFacturacion>"
                datohash = datoxml
                If es_anulacion = False Then
   
                    Print #92, "<sum:RegistroAltaFacturas>" & datoxml;
                Else
                    Print #92, "<sum:RegistroAnulacionFacturas>" & datoxml;
                End If
               
                datoxml = "<sum1:IDFactura>"
                datohash = datohash & datoxml
                Print #92, datoxml;
                .......
****AL FINAL CALCULO EL HASH USANDO LAS API DE WINDOWS****
***  CryptCreateHash, ¿¿¿CryptAcquireContext, etc... de la libreria  "advapi32.dll"*****

                huella = UCase(CreateHashString(datohash, CALG_SHA_256))
                   
*** Inserto el hash en el xml y el resto de nodos
                  Print #92, "<sum1:Huella>" & huella & "</sum1:Huella>"
                   
                    Print #92, "<sum1:TipoHash>01</sum1:TipoHash>"
                    Print #92, "</sum:DatosControl>"
                    If es_anulacion Then
                        Print #92, "</sum:RegistroAnulacionFacturas>"
                        Print #92, "</sum:BajaFactuSistemaFacturacion>"
                    Else
                        Print #92, "</sum:RegistroAltaFacturas>"
                        Print #92, "</sum:AltaFactuSistemaFacturacion>"
                    End If
                  close #92

Por otro lado puedo encapsular en php, ya que en VB6 desconozco la forma, pero en mi caso hemos pagado a una empresa la programación y el servicio de conservación y le vamos a enviar los xmls sin encapsular para que hagan toda la hilera de verificación del encadenamiento, validación schema xml-xsd, conservación, encapsulamiento, envios y control de errores, el envio lo harán con su certificado y ellos le dan este servicio a cada cliente al que le cobraremos un precio "razonable", y me libero de la parte peor. Cada cliente recibirá o podrá consultar el reporte de los envios y si hay errores se avisará y se tomará las medidas según cada caso, esto ya lo tenemos definido.

ermendalenda 17-02-2024 10:44:33

codigo ejemplo php encapsulamiento y envio
 
Aquí te dejo un encapsulamiento y envio, totalmente funcional para face y faceb2b en entornos de prueba y producción, si aprendes como funciona lo puedes modificar para cualquier definición que hagan teniendo en cuenta que yo le paso el path donde tengo el fichero y los datos por curl de esta forma:
Código:

curl --connect-timeout 10 --insecure -A "FacturaePHP/1.7.1" -H "SOAPAction: https://webservice.face.gob.es#enviarFactura" --data "@C:\xml\Facturare_FICTICIO_fichero.xml" --cert-type P12 --cert c:\....\fichero_certificado.pfx:clave -H "Content-Type: text/xml" https://se-face-webservice.redsara.es/facturasspp2 -o C:\respuestas\Respuesta_face_o.html -D C:\respuestas\Respuesta_face_D.html
Código PHP:

 <?php 
//ASIGNA EL ENTORNO QUE VAMOS A USAR  $endpoint como variable de uso GLOBALS
//************************************
//*************  FACE   **************
//************************************
//  ENTORNO DE PRODUCCION
//$endpoint= "https://webservice.face.gob.es/facturasspp2" :
      
//  ENTORNO DE PRUEBAS
$endpoint"https://se-face-webservice.redsara.es/facturasspp2";      
//************************************


//************************************
//************  FACEB2B   ************
//************************************
//  ENTORNO DE PRODUCCION
//$endpoint= "https://ws.faceb2b.gob.es/sv1/invoice" :

//  ENTORNO DE PRUEBAS
//$endpoint= "https://se-ws-faceb2b.redsara.es/sv1/invoice";
//************************************





//**Asigna a $datos la variable de la llamada curl (fichero) que contiene 2 variables separadas por signo "="
$datos $_GET['fichero'];

//***Asigno $datos a un array ya que contiene 2 campos 
$varias=explode("=",$datos);
//***El primer campo del array contiene el nombre del fichero del certificado

// **EJEMPLO PFX $dir_cert = ($_SERVER['DOCUMENT_ROOT'].'/certs/Certificado.pfx' );
//variable de uso GLOBALS
$dir_cert = ($_SERVER['DOCUMENT_ROOT'].'/certs/'.$varias[1] );

//***El segundo campo del array contiene el password del certificado
//variable de uso GLOBALS
$clave=$varias[2];

//variable de uso GLOBALS
$filename=$varias[3];
$NombreFichero=$varias[3];

//variable de uso GLOBALS
$xml2=file_get_contents("php://input");


//variable de uso GLOBALS
$version "1.7.1";

// Cargamos la factura en una instancia de FacturaeFile

//$invoice2 = new InvoiceTest();

//$invoice2->EnviarFactura($xml2);
//*****************************
//****** ENVIAR POR FACE ******
//*****************************
    
$invoice = new FacturaeFile();
    
$invoice=$GLOBALS["xml2"];


    
    
$nulo=null;
    
$face = new FaceTrait();

    
$res =$face->sendInvoice("[email protected]"$invoice);


//*****************************
//***** ENVIAR POR FACEB2B ****
//*****************************

//    $invoice = new FacturaeFile();
//    $invoice=$GLOBALS["xml2"];
//    $nulo=null;
//    $face = new FaceB2BTrait();

//    $res =$face->sendInvoice("[email protected]", $invoice);




/**
 * Gets both public and private keys from a PKCS#12 certificate store or a PEM
 * file (X.509 certificate).
 */
class KeyPairReader {
  private 
$publicChain = [];
  private 
$privateKey null;


  
/**
   * Get public certificates chain from child to top CA
   * @return string[] Array of PEM strings
   */
  
public function getPublicChain() {
    return 
$this->publicChain;
  }


  
/**
   * Get public key
   * @return string|null Certificate for the Public Key in PEM format
   */
  
public function getPublicKey() {
    return empty(
$this->publicChain) ? null $this->publicChain[0];
  }


  
/**
   * Get private key
   * @return \OpenSSLAsymmetricKey|resource|null Decrypted Private Key
   */
  
public function getPrivateKey() {
    return 
$this->privateKey;
  }


  
/**
   * KeyPairReader constructor
   *
   * @param string      $publicPath  Path to public key in PEM or PKCS#12 file
   * @param string|null $privatePath Path to private key (null for PKCS#12)
   * @param string      $passphrase  Private key passphrase
   */
  
public function __construct($publicPath$privatePath=null$passphrase="") {
    if (
is_null($privatePath)) {
      
$this->readPkcs12($GLOBALS["dir_cert"], $passphrase);
    } else {
      
$this->readX509($GLOBALS["dir_cert"], $privatePath$passphrase);
    }
  }


  
/**
   * Read a X.509 certificate and PEM encoded private key
   *
   * @param string $publicPath  Path to public key PEM file
   * @param string $privatePath Path to private key PEM file
   * @param string $passphrase  Private key passphrase
   */
  
private function readX509($publicPath$privatePath$passphrase) {
    if (!
is_file($GLOBALS["dir_cert"]) || !is_file($privatePath)) return;

    
// Validate and normalize public key
    
$publicKey openssl_x509_read(file_get_contents($GLOBALS["dir_cert"]));
    if (empty(
$publicKey)) return;
    
openssl_x509_export($publicKey$publicKeyPem);
    
$this->publicChain = array($publicKeyPem);
    
    
// Decrypt private key
    
$this->privateKey openssl_pkey_get_private(file_get_contents($privatePath), $passphrase);
  }


  
/**
   * Read a PKCS#12 Certificate Store
   *
   * @param string $certPath   The certificate store file name
   * @param string $passphrase Password for unlocking the PKCS#12 file
   */
  
private function readPkcs12($certPath$passphrase) {
    if (!
is_file($certPath)) return;
    if (
openssl_pkcs12_read(file_get_contents($certPath), $store$passphrase)) {
      
$this->publicChain = array($store['cert']);
      if (!empty(
$store['extracerts'])) {
        
$this->publicChain array_merge($this->publicChain$store['extracerts']);
      }
      
$this->privateKey openssl_pkey_get_private($store['pkey']);
      unset(
$store);
    }
  }

}
class 
XmlTools {

  
/**
   * Escape XML value
   * @param  string $value Input value
   * @return string        Escaped input
   */
  
public function escape($value) {
    return 
htmlspecialchars($valueENT_XML1'UTF-8');
  }


  
/**
   * Generate random ID
   *
   * This method is used for generating random IDs required when signing the
   * document.
   *
   * @return int Random number
   */
  
public function randomId() {
    if (
function_exists('random_int')) return random_int(0x100000000x7FFFFFFF);
    return 
rand(100000999999);
  }


  
/**
   * Inject namespaces
   * @param  string          $xml   Input XML
   * @param  string|string[] $newNs Namespaces
   * @return string                 Canonicalized XML with new namespaces
   */
  
public function injectNamespaces($xml$newNs) {
    if (!
is_array($newNs)) $newNs = array($newNs);
    
$xml explode(">"$xml2);
    
$oldNs explode(" "$xml[0]);
    
$elementName array_shift($oldNs);

    
// Combine and sort namespaces
    
$xmlns = array();
    
$attributes = array();
    foreach (
array_merge($oldNs$newNs) as $name) {
      if (
strpos($name'xmlns:') === 0) {
        
$xmlns[] = $name;
      } else {
        
$attributes[] = $name;
      }
    }
    
sort($xmlns);
    
sort($attributes);
    
$ns array_merge($xmlns$attributes);

    
// Generate new XML element
    
$xml $elementName " " implode(' '$ns) . ">" $xml[1];
    return 
$xml;
  }


  
/**
   * To Base64
   * @param  string  $bytes  Input
   * @param  boolean $pretty Pretty Base64 response
   * @return string          Base64 response
   */
  
public function toBase64($bytes$pretty=false) {
    
$res base64_encode($bytes);
    return 
$pretty $this->prettify($res) : $res;
  }


  
/**
   * Prettify
   * @param  string $input Input string
   * @return string        Multi-line resposne
   */
  
private function prettify($input) {
    return 
chunk_split($input76"\n");
  }


  
/**
   * Get digest in SHA-512
   * @param  string  $input  Input string
   * @param  boolean $pretty Pretty Base64 response
   * @return string          Digest
   */
  
public function getDigest($input$pretty=false) {
    return 
$this->toBase64(hash("sha512"$inputtrue), $pretty);
  }


  
/**
   * Get certificate
   * @param  string  $pem    Certificate for the public key in PEM format
   * @param  boolean $pretty Pretty Base64 response
   * @return string          Base64 Certificate
   */
  
public function getCert($pem$pretty=true) {
    
$pem str_replace("-----BEGIN CERTIFICATE-----"""$pem);
    
$pem str_replace("-----END CERTIFICATE-----"""$pem);
    
$pem str_replace("\n"""str_replace("\r"""$pem));
    if (
$pretty$pem $this->prettify($pem);
    return 
$pem;
  }




  
/**
   * Get signature in SHA-1
   * @param  string  $payload    Data to sign
   * @param  string  $privateKey Private Key
   * @param  boolean $pretty     Pretty Base64 response
   * @return string              Base64 Signature
   */
  
public function getSignature($payload$privateKey$pretty=true) {
    
openssl_sign($payload$signature$privateKey);
    return 
$this->toBase64($signature$pretty);
  }


}

Class 
Faceb2bTrait {
  
/**
   * Get web namespace
   * @return string Web namespace
   */
  
protected function getWebNamespace() {
    return 
"https://webservice.faceb2b.gob.es";
  }


  
/**
   * Send invoice
   * @param  FacturaeFile      $invoice    Invoice
   * @param  FacturaeFile|null $attachment Optional attachment
   * @return SimpleXMLElement              Response
   */
  
public function sendInvoice($invoice$attachment=null) {
    
$tools = new XmlTools();
    
$req '<web:SendInvoice><request>';

    
$req .= '<invoiceFile>' .
        
'<content>' $tools->toBase64($GLOBALS["xml2"]) . '</content>' .
        
'<name>' $GLOBALS["NombreFichero"] . '</name>' .
        
'<mime>text/xml</mime>' // Mandatory MIME type
      
'</invoiceFile>';

    if (!
is_null($attachment)) {
      
$req .= '<attachmentFile>' .
          
'<content>' $tools->toBase64($attachment->getData()) . '</content>' .
          
'<name>' $attachment->getFilename() . '</name>' .
          
'<mime>' $attachment->getMimeType() . '</mime>' .
        
'</attachmentFile>';
    }

    
$req .= '</request></web:SendInvoice>';
    
//$soap=new SoapClient1();
$soap = new FacturaeFile();
      
    return 
$soap->request($req);
  }


  
/**
   * Get invoice details
   * @param  string           $regId Registry number
   * @return SimpleXMLElement        Response
   */
  
public function getInvoiceDetails($regId) {
    return 
$this->request('<web:GetInvoiceDetails><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:GetInvoiceDetails>');
  }


  
/**
   * Request invoice cancellation
   * @param  string           $regId   Registry number
   * @param  string           $reason  Reason code
   * @param  string|null      $comment Optional comments
   * @return SimpleXMLElement          Response
   */
  
public function requestInvoiceCancellation($regId$reason$comment=null) {
    
$req '<web:RequestInvoiceCancellation><request>';
    
$req .= '<registryNumber>' $regId '</registryNumber>';
    
$req .= '<reason>' $reason '</reason>';
    if (!
is_null($comment)) {
      
$req .= '<comment>' $comment '</comment>';
    }
    
$req .= '</request></web:RequestInvoiceCancellation>';

    return 
$this->request($req);
  }


  
/**
   * Get registered invoices
   * @param  string|null      $receivingUnit Receiving unit code
   * @return SimpleXMLElement                Response
   */
  
public function getRegisteredInvoices($receivingUnit=null) {
    
$req '<web:GetRegisteredInvoices><request>';
    if (
is_null($receivingUnit)) {
      
$req .= '<receivingUnit>' $receivingUnit '</receivingUnit>';
    }
    
$req .= '</request></web:GetRegisteredInvoices>';
    return 
$this->request($req);
  }


  
/**
   * Get invoice cancellations
   * @return SimpleXMLElement Response
   */
  
public function getInvoiceCancellations() {
    return 
$this->request('<web:GetInvoiceCancellations><request>' .
      
'</request></web:GetInvoiceCancellations>');
  }


  
/**
   * Download invoice
   * @param  string           $regId    Registry number
   * @param  boolean          $validate Validate invoice
   * @return SimpleXMLElement           Response
   */
  
public function downloadInvoice($regId$validate=true) {
    
$req '<web:DownloadInvoice><request>';
    
$req .= '<registryNumber>' $regId '</registryNumber>';
    if (
$validate) {
      
$req .= '<signatureValidationMode>validate</signatureValidationMode>';
    }
    
$req .= '</request></web:DownloadInvoice>';
    return 
$this->request($req);
  }


  
/**
   * Confirm invoice download
   * @param  string           $regId   Registry number
   * @return SimpleXMLElement          Response
   */
  
public function confirmInvoiceDownload($regId) {
    return 
$this->request('<web:ConfirmInvoiceDownload><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:ConfirmInvoiceDownload>');
  }


  
/**
   * Reject invoice
   * @param  string           $regId   Registry number
   * @param  string           $reason  Reason code
   * @param  string|null      $comment Optional comments
   * @return SimpleXMLElement          Response
   */
  
public function rejectInvoice($regId$reason$comment=null) {
    
$req '<web:RejectInvoice><request>';
    
$req .= '<registryNumber>' $regId '</registryNumber>';
    
$req .= '<reason>' $reason '</reason>';
    if (!
is_null($comment)) {
      
$req .= '<comment>' $comment '</comment>';
    }
    
$req .= '</request></web:RejectInvoice>';
    return 
$this->request($req);
  }


  
/**
   * Mark invoice as paid
   * @param  string           $regId   Registry number
   * @return SimpleXMLElement          Response
   */
  
public function markInvoiceAsPaid($regId) {
    return 
$this->request('<web:MarkInvoiceAsPaid><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:MarkInvoiceAsPaid>');
  }


  
/**
   * Accept invoice cancellation
   * @param  string           $regId   Registry number
   * @return SimpleXMLElement          Response
   */
  
public function acceptInvoiceCancellation($regId) {
    return 
$this->request('<web:AcceptInvoiceCancellation><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'</request></web:AcceptInvoiceCancellation>');
  }


  
/**
   * Reject invoice cancellation
   * @param  string           $regId   Registry number
   * @param  string           $comment Comment
   * @return SimpleXMLElement          Response
   */
  
public function rejectInvoiceCancellation($regId$comment) {
    return 
$this->request('<web:RejectInvoiceCancellation><request>' .
      
'<registryNumber>' $regId '</registryNumber>' .
      
'<comment>' $comment '</comment>' .
      
'</request></web:RejectInvoiceCancellation>');
  }



  
/**
   * Get codes
   * @param  string           $type Code type
   * @return SimpleXMLElement       Response
   */
  
public function getCodes($type="") {
    return 
$this->request('<web:GetCodes><request>' .
      
'<codeType>' $type '</codeType>' .
      
'</request></web:GetCodes>');
  }
}
//trait FaceTrait {
class FaceTrait {
  
/**
   * Get web namespace
   * @return string Web namespace
   */
  
protected function getWebNamespace() {
    return 
"https://webservice.face.gob.es";
  }
  
/**
   * Send invoice
   * @param  string           $email       Email address
   * @param  FacturaeFile     $invoice     Invoice
   * @param  FacturaeFile[]   $attachments Attachments
   * @return SimpleXMLElement              Response
   */
  
public function sendInvoice($email$invoice$attachments=array()) {
    
$tools = new XmlTools();
    
$req '<web:enviarFactura><request>';
    
$req .= '<correo>' $email '</correo>';
    
$req .= '<factura>' .
        
'<factura>' $tools->toBase64($GLOBALS["xml2"]) . '</factura>' .
        
'<nombre>' $GLOBALS["NombreFichero"] . '</nombre>' .
        
'<mime>application/xml</mime>' // Mandatory MIME type
      
'</factura>';
    
$req .= '<anexos>';
    foreach (
$attachments as $file) {
      
$req .= '<anexo>' .
          
'<anexo>' $tools->toBase64($file->getData()) . '</anexo>' .
          
'<nombre>' $file->getFilename() . '</nombre>' .
          
'<mime>' $file->getMimeType() . '</mime>' .
        
'</anexo>';
    }
    
$req .= '</anexos>';
    
$req .= '</request></web:enviarFactura>';

//echo "*** Esta es la variable de envio req: ";
//echo $req;
//echo " *** FIN VARIABLE REQ *** ";


    //$soap=new SoapClient1();
    
$soap = new FacturaeFile();
      
    
$ok=$soap->request($req);
  }


  
/**
   * Cancel invoice 
   * @param  string           $regId  Invoice register ID
   * @param  string           $reason Cancelation reason
   * @return SimpleXMLElement         Response
   */
  
public function cancelInvoice($regId$reason) {
    return 
$this->request('<web:anularFactura>' .
      
'<numeroRegistro>' $regId '</numeroRegistro>' .
      
'<motivo>' $reason '</motivo>' .
      
'</web:anularFactura>');
  }

  
/**
   * Get invoice status codes
   * @return SimpleXMLElement Response
   */
  
public function getStatus() {
    return 
$this->request('<web:consultarEstados></web:consultarEstados>');
  }


  
/**
   * Get administrations
   * @param  boolean          $onlyTopLevel Get only top level administrations
   * @return SimpleXMLElement               Response
   */
  
public function getAdministrations($onlyTopLevel=true) {
    
$tag "consultarAdministraciones";
    if (!
$onlyTopLevel$tag .= "Repositorio";
    return 
$this->request("<web:$tag></web:$tag>");
  }


  
/**
   * Get units
   * @param  string|null      $code Administration code
   * @return SimpleXMLElement       Response
   */
  
public function getUnits($code=null) {
    if (
is_null($code)) return $this->request('<web:consultarUnidades></web:consultarUnidades>');
    return 
$this->request('<web:consultarUnidadesPorAdministracion>' .
      
'<codigoDir>' $code '</codigoDir>' .
      
'</web:consultarUnidadesPorAdministracion>');
  }


  
/**
   * Get NIFs
   * @param  string|null      $code Administration code
   * @return SimpleXMLElement       Response
   */
  
public function getNifs($code=null) {
    if (
is_null($code)) return $this->request('<web:consultarNIFs></web:consultarNIFs>');
    return 
$this->request('<web:consultarNIFsPorAdministracion>' .
      
'<codigoDir>' $code '</codigoDir>' .
      
'</web:consultarNIFsPorAdministracion>');
  }


  
/**
   * Get invoice
   * @param  string|string[]  $regId Invoice register ID(s)
   * @return SimpleXMLElement        Response
   */
  
public function getInvoices($regId) {
    if (
is_string($regId)) {
      return 
$this->request('<web:consultarFactura>' .
        
'<numeroRegistro>' $regId '</numeroRegistro>' .
        
'</web:consultarFactura>');
    }
    
$req '<web:consultarListadoFacturas><request>';
    foreach (
$regId as $id$req .= '<numeroRegistro>' $id '</numeroRegistro>';
    
$req .= '</request></web:consultarListadoFacturas>';
    return 
$this->request($req);
  }



}
trait 
StageableTrait {
  private 
$production true;

  
/**
   * Set production environment
   * @param boolean $production Is production
   */
  
public function setProduction($production) {
    
$this->production $production;
  }


  
/**
   * Is production
   * @return boolean Is production
   */
  
public function isProduction() {
    return 
$this->production;
  }
}
/**
 * Facturae File
 *
 * Represents a file that can be used as an attachment for an invoice or to
 * send information to a Web Service.
 */
class FacturaeFile {
  const 
REQUEST_EXPIRATION 60// In seconds

  
private $publicKey;
  private 
$privateKey;

  private 
$filename;
  private 
$data;
  private 
$mime;

/**
   * Get web namespace
   * @return string Web namespace
   */
  
protected function getWebNamespace() {
    return 
"https://webservice.face.gob.es";
  }


public function 
request($body) {

$tools = new XmlTools();
    

$nulo=null;


//DATOS SIGN

$policy= array(
    
"name" => "Politica de Firma FacturaE v3.1",
    
"url" => "http://www.facturae.es/politica_de_firma_formato_facturae/politica_de_firma_formato_facturae_v3_1.pdf",
    
"digest" => "Ohixl6upD6av8N7pEvDABhEL6hM=");
    
// Generate random IDs
    
    // Load public and private keys
    
$reader = new KeyPairReader($GLOBALS["dir_cert"], $nulo$GLOBALS["clave"]);
    
$publicChain2 $reader->getPublicChain();
    
$privateKey2 $reader->getPrivateKey();
    
$signPolicy2 $policy;
    unset(
$reader);


    
//No usado Comprueba si hay key publica y privada y devueleve 1=hay 0=no hay
    //return (!empty($publicChain2) && !empty($privateKey2));


    
$reader = new KeyPairReader($GLOBALS["dir_cert"], null$GLOBALS["clave"]);
    
//$publicChain1 = $reader->getPublicChain();
    
$publicKey1 $publicChain2;
     
$publicChain1 $publicChain2;

    
$privateKey1 $reader->getPrivateKey();
    
$signPolicy1 $signPolicy2;
    unset(
$reader);

    
$tools = new XmlTools();

    
// Generate random IDs for this request
    
$bodyId "BodyId-" $tools->randomId();
    
$certId "CertId-" $tools->randomId();
    
$keyId "KeyId-" $tools->randomId();
    
$strId "SecTokId-" $tools->randomId();
    
$timestampId "TimestampId-" $tools->randomId();
    
$sigId "SignatureId-" $tools->randomId();

    
// Define namespaces array
    
$ns = array(
      
"soapenv" => 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"',
      
"web" => 'xmlns:web="' $this->getWebNamespace() . '"',
      
"ds" => 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#"',
      
"wsu" => 'xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"',
      
"wsse" => 'xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"'
    
);

    
// Generate request body
    
$reqBody '<soapenv:Body wsu:Id="' $bodyId '">' $body '</soapenv:Body>';
    
$bodyDigest $tools->getDigest($tools->injectNamespaces($reqBody$ns));

    
// Generate timestamp
    
$timeCreated time();
    
$timeExpires $timeCreated self::REQUEST_EXPIRATION;
    
$reqTimestamp '<wsu:Timestamp wsu:Id="' $timestampId '">' .
        
'<wsu:Created>' date('c'$timeCreated) . '</wsu:Created>' .
        
'<wsu:Expires>' date('c'$timeExpires) . '</wsu:Expires>' .
      
'</wsu:Timestamp>';
    
$timestampDigest $tools->getDigest(
      
$tools->injectNamespaces($reqTimestamp$ns)
    );

    
// Generate request header
    
$reqHeader '<soapenv:Header>';
    
$reqHeader .= '<wsse:Security soapenv:mustUnderstand="1">' ;
    
$reqHeader .= '<wsse:BinarySecurityToken ' .
      
'EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ' .
      
'wsu:Id="' $certId '" ' .
      
'ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">' .
        
$tools->getCert($publicKey1[0], false) .
      
'</wsse:BinarySecurityToken>';

    
// Generate signed info
    
$signedInfo '<ds:SignedInfo>' .
        
'<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">' .
        
'</ds:CanonicalizationMethod>' .
        
'<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>' .
        
'<ds:Reference URI="#' $timestampId '">' .
          
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"></ds:DigestMethod>' .
          
'<ds:DigestValue>' $timestampDigest '</ds:DigestValue>' .
        
'</ds:Reference>' .
        
'<ds:Reference URI="#' $bodyId '">' .
          
'<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"></ds:DigestMethod>' .
          
'<ds:DigestValue>' $bodyDigest '</ds:DigestValue>' .
        
'</ds:Reference>' .
      
'</ds:SignedInfo>';
    
$signedInfoPayload $tools->injectNamespaces($signedInfo$ns);

    
// Add signature and KeyInfo to header
    
$reqHeader .= '<ds:Signature Id="' $sigId '">' .
      
$signedInfo .
      
'<ds:SignatureValue>' .
        
$tools->getSignature($signedInfoPayload$privateKey1false) .
      
'</ds:SignatureValue>';
    
$reqHeader .= '<ds:KeyInfo Id="' $keyId '">' .
      
'<wsse:SecurityTokenReference wsu:Id="' $strId '">' .
        
'<wsse:Reference URI="#' $certId '" ' .
        
'ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">' .
        
'</wsse:Reference>' .
      
'</wsse:SecurityTokenReference>' .
      
'</ds:KeyInfo>';
    
$reqHeader .= '</ds:Signature>';

    
// Add timestamp and close header
    
$reqHeader .= $reqTimestamp;
    
$reqHeader .= '</wsse:Security>';
    
$reqHeader .= '</soapenv:Header>';

    
// Generate final request
    
$req '<soapenv:Envelope>' $reqHeader $reqBody '</soapenv:Envelope>';
    
$req $tools->injectNamespaces($req$ns);
    
$req '<?xml version="1.0" encoding="UTF-8"?>' $req;

    
// Extract SOAP action from "<web:ACTION></web:ACTION>"
    
$soapAction substr($body5strpos($body'>')-5);
    
$soapAction $this->getWebNamespace() . "#$soapAction";

    
$ch curl_init();
    
curl_setopt_array($ch, array(
      
CURLOPT_URL => $GLOBALS['endpoint'],
      
CURLOPT_RETURNTRANSFER => 1,
      
CURLOPT_SSL_VERIFYPEER => 0,
      
CURLOPT_TIMEOUT => 30,
      
CURLOPT_POST => 1,
      
CURLOPT_POSTFIELDS => $req,
      
CURLOPT_HTTPHEADER => array(
        
"Content-Type: text/xml",
        
"SOAPAction: " $soapAction
      
),
      
CURLOPT_USERAGENT => "FacturaePHP/" $GLOBALS["version"]
    ));
    
$res curl_exec($ch);
    
curl_close($ch);
    unset(
$ch);


    
//// Parse response
    
    
$xml = new \DOMDocument();
    
$xml->loadXML($res);
    
$xml $xml->getElementsByTagName('Body')->item(0)->getElementsByTagName('*')->item(0);
$child $xml->getElementsByTagName('codigo');
 
foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }
    
$child $xml->getElementsByTagName('descripcion');

foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }
    
$child $xml->getElementsByTagName('codigo Seguimiento');

foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }
    
$child $xml->getElementsByTagName('codigoSeguimiento');

foreach (
$child as $chi
{
    echo 
$chi->nodeName "=" $chi->nodeValue "\r\n" ;
 }


//echo  "---- FIN RESULTADO ----"  . "\r\n" . "---- RESPUESTA COMPLETA  ----"  . "\r\n" . $res . "\r\n" . "---- FIN RESPUESTA COMPLETA ----" .  $req;

//if ($res->resultado->codigo == 0) {
//  // La factura ha sido aceptada
//  echo "Número de registro => " . $res->factura->numeroRegistro;
//} else {
//  // FACe ha rechazado la factura
//}

//return $req;  
}



  
/**
   * Get data
   * @return string Data
   */
  
public function getData() {
    return 
$this->data;
  }


  
/**
   * Get filename
   * @return string Filename
   */
  
public function getFilename() {
    return 
$this->filename;
  }


  
/**
   * Get MIME type
   * @return string MIME type
   */
  
public function getMimeType() {
    return 
$this->mime;
  }
}




?>

[/php]


La franja horaria es GMT +2. Ahora son las 14:50:26.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi