Page 1 of 2

Firmar facturae

Posted: Thu Nov 29, 2018 1:04 pm
by manuelcalerosolis
Hola a todos,

Me gustaría automatizar cada el proceso de creación y envió de facturas electrónicas, ya q cada vez se usan mas.

Hasta ahora obligaba a mis clientes a firmar las facturas con el programa externo Autofirma, pero es un proceso manual donde tienen q localizar el XML, y muchos se me pierden.

Ademas q no me parece serio, y quiero preguntaros si alguno, ¿ habéis avanzado en este tema de firmar la factura, desde dentro de la propia aplicación?

Muchas gracias

Re: Firmar facturae

Posted: Thu Nov 29, 2018 2:49 pm
by karinha

Re: Firmar facturae

Posted: Thu Nov 29, 2018 3:57 pm
by José Vicente Beltrán
Yo utilizo una llamada a 'autofirma' desde la línea de comandos, dentro de mi aplicación FW y todo de forma transparente para el usuario

autofirmacommandline sign -i %1 -o %2 -format facturae -store windows -alias %3

%1 -> ruta+nombre del archivo XML sin firmar
%2 -> ruta+nombre del archivo XML una vez firmado
%3 -> alias del certificado obtenido directamente del código proporcionado por DarioFlores en el enlace indicado por Karinha mas arriba.

funciona sorprendentemente bien y con apariencia totalmente profesional, la ventaja es que cuando cambie la normativa de firmaE solo hay que actualizar 'autofirma' y ya está.

Re: Firmar facturae

Posted: Fri Nov 30, 2018 7:01 pm
by manuelcalerosolis
José Vicente y karinha gracias por vuestro interés.

Intento ejecutar el "autofirmacommandline" pero me dice q el alias del certificado no es valido, y realmente lo que le paso al comando es lo q me devuelve, la función publicada por karinha.

No se hay ninguna entrada en el almacen con el alias indicado: XXXXXX XXXXX XXXXXXX - 99999999X

Por el contrario en el programa de autofirma con gui, funciona perfectamente, me solicita el fichero a firmar, y me saca las firmas presentes en mi sistema.

La manera en la q monto el comando es esta, no se si algo esta mal

autofirmacommandline sign -i c:\temp\andrew.xml -o c:\temp\andrew-signed.xml -format facturae -store windows -alias "XXXXXX XXXXX XXXXXXX - 99999999X"

Saludos

Re: Firmar facturae

Posted: Sat Dec 01, 2018 1:19 am
by Tito
Manuel

Mira este link, talvez te resuelve tu problema
https://www.example-code.com/foxpro/xad ... 3_2_es.asp

saludos
Héctor

Re: Firmar facturae

Posted: Sun Dec 02, 2018 10:21 am
by manuelcalerosolis
Hector,

Gracias por tu respuesta, voy a seguir intentado el tema con Autofirma, pq realmente es facturae hay cambios constantes, y me gusta mas la idea de usar el comando.

A ver si logro saber lo q pasa, y acaba reconociendo la el certificado.

Saludos

Re: Firmar facturae

Posted: Sun Dec 02, 2018 8:54 pm
by AngelSalom
Me quedo en el hilo, interesante intentar la automatización con Autofirma.

Re: Firmar facturae

Posted: Mon Dec 03, 2018 10:33 am
by José Vicente Beltrán
Manuel, yo utilizo el siguiente código y funciona sin problemas.

Code: Select all

 ...
        if FILE( xFileOrigen )
            lChDir( cFilePath(xRutaBAT) )

            if file(cFilePath(xRutaBAT)+"Autofirma.exe")

                cCertif := SelCertif(SELCERT())                                                           
                cCertif := UPPER(alltrim(cCertif))

            else
                cCertif := ""
            endif

            if !empty(cCertif)
                WaitRun( xRutaBAT+' "'+xFileOrigen+'" "'+xFileDestino+'" "'+cCertif+'"')              // firmando la factura con autofirma
            endif
            lChDir( cDirecDatos )
        else
            msgInfo( "Archivo XML no generado", "Aviso")
            return .t.
        endif

//LLamada a la funcion de seleccion de certificados: SelCertif(SELCERT())

//*****************************************************************************
function SelCertif( uVal )

   local cType := ValType( uVal )

   do case
      case cType == "C" .or. cType == "M"
           return uVal                         // devuelve el alias del certificado seleccionado

      case cType == "D"
           return DToC( uVal )

      case cType == "L"
           return If( uVal, ".T.", ".F." )

      case cType == "N"
           return AllTrim( Str( uVal ) )

      case cType == "B"
           return "{|| ... }"

      case cType == "A"
           return "{ ... }"

      case cType == "O"
           return If( __ObjHasData( uVal, "cClassName" ), uVal:cClassName, uVal:ClassName() )

      case cType == "H"
           return "{=>}"

      otherwise
           return ""
   endcase

return nil

//*****************************************************************************
//*****************************************************************************

#pragma BEGINDUMP

#include <windows.h>
//#include <psapi.h>
//#include <hbapi.h>
//#include <hbapierr.h>
//#include <hbapiitm.h>
//#include <wincrypt.h>

#define CRYPTUI_SELECT_LOCATION_COLUMN 0x000000010

//Definir el prototipo de las funciones:
typedef HCERTSTORE (WINAPI * PTYPECERTOPEN) (HCRYPTPROV, LPTSTR);
typedef PCCERT_CONTEXT (WINAPI * PTYPECERTSELECTDLG) (HCERTSTORE, HWND, LPCWSTR, LPCWSTR, DWORD, DWORD, void*);
typedef PCCERT_CONTEXT (WINAPI * PTYPECERTENUM) (HCERTSTORE, PCCERT_CONTEXT);
typedef DWORD (WINAPI * PTYPECERTGETNAME) (PCCERT_CONTEXT, DWORD, DWORD, VOID*, LPTSTR, DWORD);
typedef DWORD (WINAPI * PTYPECERTNAMETOSTR) (DWORD, PCERT_NAME_BLOB, DWORD, LPTSTR, DWORD);
typedef BOOL (WINAPI * PTYPECERTFREECC) (PCCERT_CONTEXT);
typedef BOOL (WINAPI * PTYPECERTCLOSESTORE) (HCERTSTORE, DWORD);

HB_FUNC(SELCERT)
{

   // Hay varios ejemplos en: https://msdn.microsoft.com/en-us/librar ... 61(v=vs.85).aspx

   HCERTSTORE hStore;
   PCCERT_CONTEXT PrevContext, CurContext;
   PCHAR sNombre;
   DWORD cbSize;
   PHB_ITEM pArray;
   PHB_ITEM pItem;
   PCCERT_CONTEXT   pCertContext;
   // Cargamos las librerías de las que queremos la dirección de las funciones.
   HMODULE HCrypt = LoadLibrary("Crypt32.dll");
   HMODULE HCrypt2 = LoadLibrary("Cryptui.dll");

   // Declaramos el tipo de puntero a la función, tenemos la definición arriba.
   PTYPECERTOPEN    pCertOpen;
   PTYPECERTSELECTDLG    pCertSelectDlg;
   PTYPECERTGETNAME pCertGetName;
   PTYPECERTNAMETOSTR pCertNameToStr;
   PTYPECERTFREECC pCertFreeCC;
   PTYPECERTCLOSESTORE pCertCloseStore;


   if (HCrypt != NULL && HCrypt2 != NULL){
      //Sacamos el puntero todas las funciones que vamos a usar mediante GetProcAddress:
      #ifdef UNICODE
         pCertOpen    = (PTYPECERTOPEN) GetProcAddress(HCrypt, "CertOpenSystemStoreW");
         pCertGetName = (PTYPECERTGETNAME) GetProcAddress(HCrypt, "CertGetNameStringW");
      #else
         pCertOpen    = (PTYPECERTOPEN) GetProcAddress(HCrypt, "CertOpenSystemStoreA");
         pCertGetName = (PTYPECERTGETNAME) GetProcAddress(HCrypt, "CertGetNameStringA");
      #endif
      pCertSelectDlg = (PTYPECERTSELECTDLG) GetProcAddress(HCrypt2, "CryptUIDlgSelectCertificateFromStore");
      pCertFreeCC  = (PTYPECERTFREECC) GetProcAddress(HCrypt, "CertFreeCertificateContext");
      pCertCloseStore  = (PTYPECERTCLOSESTORE) GetProcAddress(HCrypt, "CertCloseStore");
   }

   if (pCertOpen){
      // Llamada a CertOpenSystemStore:
      hStore = pCertOpen(NULL, TEXT("MY"));
   }

   if (hStore){
      // Diálogo de selección de certificado:
      pCertContext = pCertSelectDlg(hStore, NULL, NULL, NULL, CRYPTUI_SELECT_LOCATION_COLUMN, 0, NULL);

      if (pCertContext){
         cbSize = pCertGetName(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0);
         if (cbSize>0) {
            //Reservamos la memoria que necesitamos para el texto que recibiremos
            sNombre = (LPTSTR)malloc(cbSize * sizeof(TCHAR));

            pCertGetName(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, sNombre, cbSize);

            // Llamada a CertFreeCertificateContext:
            pCertFreeCC(pCertContext);
         }
      }

      // Cerrar el almacen de certificados:
      // Llamada a CertCloseStore:
      pCertCloseStore(hStore, 0);
    }

    FreeLibrary(HCrypt);
    FreeLibrary(HCrypt2);

    hb_retc(sNombre);

}

#pragma ENDDUMP

 
:shock:

Re: Firmar facturae

Posted: Mon Dec 03, 2018 9:39 pm
by manuelcalerosolis
Jose Vicente,

Pero no usas Autofirmacommandline.exe ?

Saludos

Re: Firmar facturae

Posted: Tue Dec 04, 2018 11:31 am
by José Vicente Beltrán
Claro que si, la linea de codigo siguiente llama al .bat que ejecuta autofirmacommanline.exe
xRutaBat -> ruta + nombre del .bat

Code: Select all

WaitRun( xRutaBAT+' "'+xFileOrigen+'" "'+xFileDestino+'" "'+cCertif+'"')
el .BAT contiene la siguiente linea
autofirmacommandline sign -i %1 -o %2 -format facturae -store windows -alias %3

:shock:

Re: Firmar facturae

Posted: Tue Dec 11, 2018 12:11 pm
by manuelcalerosolis
José Vicente,

Funciono perfecto, el tema era q tenia q instalar otro certificado con el q yo tenia, en mi pc, no funcionaba.

Mil gracias.

Re: Firmar facturae

Posted: Sat Dec 15, 2018 4:20 pm
by Xevi
José Vicente,

compilando y ejecutando tu ejemplo, se lanza correctamente el diálogo de selección de certificado, pero... si salgo del diálogo cancelando, para "abortar" el seguimiento de la firma, el retorno no es Empty(cCertif)... y el proceso sigue pasando igualmente por Waitrun()

El valor que se recibe de SelCertif(SELCERT()) nunca es Empty(), pero no se como hacer o cambiar para poder detectar cuando se pulsa en Cancelar del diálogo de Selección de Certificado.

Alguna ayuda???
Alguien más utiliza esa función y lo puede probar???

Gracias por vuestro tiempo.

Re: Firmar facturae

Posted: Sun Dec 16, 2018 8:36 am
by AngelSalom
Lo he probado y, efectivamente, al pulsar Cancelar en la selección del certificado la variable se carga con caracteres extraños.

Re: Firmar facturae

Posted: Sun Dec 16, 2018 9:24 am
by Xevi
Yo de momento lo soluciono cambiando

if !empty(cCertif)
...

por...

If empty(cCertif) .or. "Ä" $ cCertif .or. "ý" $ cCertif .or. "ô" $ cCertif .or. "€" $ cCertif
Else
...

Pero seria bueno poder cazar ese valor retornado como vacio o nulo para su posterior tratamiento, seria lo correcto.

Re: Firmar facturae

Posted: Wed Dec 19, 2018 3:48 pm
by Xevi
Puestos con el tema de Facturae,...
Cómo o de dónde obteneis/localizais los códigos DIR3 ???
(DIR3 Código de unidad orgánica)
son imprescindibles para el envio de facturas a entidades tales como ayuntamientos, al menos aquí donde yo estoy en fase Beta del envío de facturas electrónicas.

Seria bueno, y seguro que posible, disponer de una consulta a una web donde solicitar los datos DIR3 correspondiente a un CIF.
Como quien solicita la IP!!! jejeje
Demasiado pedir!!!

Gracias por vuestro tiempo.