Generacion de mensaje CMS Factura Electronica AFIP

2,633 views
Skip to first unread message

cmo...@factorip.com

unread,
Nov 7, 2013, 1:28:03 PM11/7/13
to php...@googlegroups.com
Hola que tal, me encuentro desarrollando la facturación electrónica en php, siguiendo los ejemplos que la afip brinda en su pagina, la cuestión es que cuando quiero generar el TRA (Ticket de Requerimiento de Acceso), ocurre el sigiente error:

        Warning: openssl_pkcs7_sign() [function.openssl-pkcs7-sign]: error getting private key in C:\ ...

La función, donde ocurre el error es la siguiente:

 $STATUS = openssl_pkcs7_sign("TRA.xml", ".TRA.tmp", "file://".self::CERT,
      array("file://".self::PRIVATEKEY, self::PASSPHRASE),
      array(),
      !PKCS7_DETACHED
 );

Donde CERT = 'cert.crt' , PRIVATEKEY = 'cert.key' y PASSPHRASE = ' '. Previamente genere la clave privada y el certificado CSR desde mi pc y los envié al email de la afip para que me entreguen el certificado x.509 para utilizarlo en el entorno de Testing. Esta misma consulta la realice en la afip y me respondieron lo siguiente:

 "Los ejemplos que publicamos son contribuciones de fuente
abierta y como tales, no incluyen soporte ni garantía de buen funcionamiento,
esto es, si Ud. decide usar cualquiera de esos ejemplos, es vuestra
responsabilidad implementarlos en vuestro propio entorno.
Aclarado esto, podemos decirle que ese error parecería indicar que el archivo
que debería contener la clave privada correspondiente al certificado no
resulta accesible (no existe en ese path, no es legible, no contiene la clave
privada, no está en formato PEM, etc. etc.)"

Y me dejo pensando esta parte "no está en formato PEM", el tema es que la afip te devuelve el certificado x.509 en formato crt, no se deberia cambiarlo o que???


Saludos,
Cristian. 

Juan Chapar

unread,
Apr 17, 2015, 10:48:10 AM4/17/15
to php...@googlegroups.com
Hola Cristian , estoy teniendo el mismo problema , encontrastes alguna asolucion para este tema?Si la encontrastes me podrias decir como hicistes.

Gracias

Alejandro Briuschi

unread,
Apr 17, 2015, 11:17:11 AM4/17/15
to php...@googlegroups.com

Hola gente, buen día. Perdón que me entrometa en la conversación con otra cosa que nada que ver. Existe un grupo de Whatsapp del foro?
Gracias!


El vie., 17 de abril de 2015 11:48, Juan Chapar <marketin...@gmail.com> escribió:
Hola Cristian , estoy teniendo el mismo problema , encontrastes alguna asolucion para este tema?Si la encontrastes me podrias decir como hicistes.

Gracias

--
Has recibido este mensaje porque estás suscrito al grupo "Grupo PHP Argentina" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a php-arg+u...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a php...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/php-arg.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

rfro...@efactory.com.ar

unread,
Apr 29, 2015, 7:36:35 AM4/29/15
to php...@googlegroups.com
Buenas Noches, tengo el mismo problema, tuvieron alguna solución.

Saludos!

Omar Virili

unread,
Apr 29, 2015, 8:37:29 PM4/29/15
to php...@googlegroups.com
Hola Cristian yo tambien estoy teniendo el mismo problema y me pregunto si lo pudiste solucionar y de ser asi si podes compartirla. Gracias
Message has been deleted

Gabriel Divenuto

unread,
Apr 30, 2015, 3:58:36 PM4/30/15
to php...@googlegroups.com
https://code.google.com/p/pyafipws/source/browse/ejemplos/factura_electronica.php

No lo he utilizado aún, estoy investigando y siguiendo este hilo.

El 30 de abril de 2015, 9:22, LBR-Linux <misae...@gmail.com> escribió:
Buenas, creo que los impresentables de la AFIP no publicaron ningún ejemplo de FEv1 en PHP, el ejemplo solamente es para .NET, la versión anterior de FE la cual si tenia ejemplos en PHP me parece que ya no corre mas.

Les recomiendo que vean http://www.pyafipws.com.ar/wsfev1 es un proyecto de codigo abierto desarrollado en python dirigido por Mariano Reingart.

--
Has recibido este mensaje porque estás suscrito al grupo "Grupo PHP Argentina" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a php-arg+u...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a php...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/php-arg.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
Gabriel E. Divenuto
Web: www.sistemasgd.com

Omar Virili

unread,
May 5, 2015, 7:39:49 AM5/5/15
to php...@googlegroups.com
Hola Cristian pudiste resolver este problema, lograste saber si es que es necesario convertir los certificados a tipo PEM. Desde ya muchas gracias.


El jueves, 7 de noviembre de 2013, 15:28:03 (UTC-3), Cristian Moreno escribió:

Pablo Micolini

unread,
May 19, 2015, 7:34:38 AM5/19/15
to php...@googlegroups.com
Les dejo el código que permite hacer el login y sacar una factura en PHP, está copiado de un proyecto interno, por lo que sirve para guiarlos hacia el camino correcto, y no es el camino correcto de por si.

Saludos.
///////////////////////////////////////
public function getCAE(){
global $ari;
//seteo las variables.
$this->CANT_REGISTROS = 1; //$cantidad_registros
$this->PRESTA_SERV = 0;
$moneda = new currency_currency($this->MONEDA);
$this->MONEDA_AFIP = $moneda->get('codigo_afip');
/////////////////////////////////tipos de documentos/////////////////////////////////////////////
# 80 - CUIT 86 - CUIL 87 - CDI 89 - LE 90 - LC 91 - CI extranjera 92 - en trámite
    # 93 - Acta nacimiento 95 - CI Bs. As. RNP 96 - DNI  94 - Pasaporte 00 - CI Policía Federal
# 01 - CI Buenos Aires 07 - CI Mendoza 08 - CI La Rioja 09 - CI Salta 10 - CI San Juan
# 11 - CI San Luis 12 - CI Santa Fe 13 - CI Santiago del Estero 14 - CI Tucumán 16 - CI Chaco
# 17 - CI Chubut  18 - CI Formosa 19 - CI Misiones 20 - CI Neuquén
////////////////////////////////////////////////////////////////////////////////////////////////
$this->TIPO_DOC = 80; //cuit
    $this->IMP_TOTAL_CONCEPTOS = 0;    
    $this->IMP_LIQUIDADO_RNI = 0.0;
    $this->IMP_OPERACIONES_EXCENTAS = 0.0;
//se arma el xml del TRA y se lo guarda en un archivo (TRA_DIR) 
$TRA = new SimpleXMLElement(
    '<?xml version="1.0" encoding="UTF-8"?>' .
    '<loginTicketRequest version="1.0">'.
    '</loginTicketRequest>');
$TRA->addChild( 'header' );
$TRA->header->addChild( 'uniqueId', date('U') );
$TRA->header->addChild( 'generationTime', date('c',date('U')-600) );
$TRA->header->addChild( 'expirationTime', date('c',date('U')+600) );
$TRA->addChild( 'service', $this->SERVICE );
$TRA->asXML( $this->TRA_DIR ); //se graba el archivo
$STATUS = openssl_pkcs7_sign( $this->TRA_DIR, $this->TMP_TRA_DIR,$this->CERT,
array($this->PRIVATEKEY, $this->PASSPHRASE),
array(),
!PKCS7_DETACHED
);
if (!$STATUS) 
{
$this->error()->addError("ERROR_PKCS7",true);  
}
 
$inf = fopen( $this->TMP_TRA_DIR, "r");
$w = 0;
$CMS = "";
 
while(!feof($inf)) 
 $buffer = fgets($inf);
 if ( $w++ >= 4 ) {
$CMS.=$buffer;
}
}
fclose($inf);
unlink( $this->TRA_DIR );
unlink( $this->TMP_TRA_DIR );
 
$client_wsaa = new SoapClient( $this->WSDL_WSAA );
 
$results = $client_wsaa->loginCms(array('in0'=>$CMS));
if (!file_put_contents( $this->TA, $results->loginCmsReturn)){
$this->error()->addError("NO_WRITE_TA",true);
}  
if (is_soap_fault($results))
{
$this->error()->addError("FALLO WSAA",true);
}
$ta_xml = simplexml_load_string($results->loginCmsReturn);
$this->TOKEN = $ta_xml->credentials->token;
$this->SIGN = $ta_xml->credentials->sign;
$this->QTY = 1;
$this->ULT_NRO = 1;
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
$client_wsfe = new SoapClient( $this->WSDL_WSFE , array( 
'trace' => true,
'encoding' => 'UTF-8',
'cache_wsdl' => WSDL_CACHE_BOTH,
//'ssl_method' => SOAP_SSL_METHOD_SSLv3,
'stream_context' => stream_context_create($opts),
"exceptions" => false
 ) ); 
$results_CMPRequest = $client_wsfe->FECompUltimoAutorizado(
array('Auth' =>  
array(
 'Token'    => $this->TOKEN,
 'Sign'     => $this->SIGN,
 'Cuit'     => $this->CUIT_EMISOR
 ),
 'PtoVta'   => $this->PTO_VTA,
 'CbteTipo' => $this->TIPO_CBTE 
 )
);
file_put_contents( microtime(true)  . '_results_CMPRequest.txt',var_export($results_CMPRequest,true));
file_put_contents( microtime(true)  . '_results_CMPRequest_soap.txt',var_export($client_wsfe,true));

if ( !isset($results_CMPRequest->FECompUltimoAutorizadoResult->CbteNro))
{
$this->error()->addError( var_export($results_CMPRequest,true),true); 
}
$this->LastCBTE = $results_CMPRequest->FECompUltimoAutorizadoResult->CbteNro;
/* $suma = $this->IMP_NETO + $this->IMP_LIQUIDADO;
if( $suma !=  $this->IMP_TOTAL)
{
// $this->IMP_NETO = $this->IMP_TOTAL - $this->IMP_LIQUIDADO;
$this->IMP_NETO = $this->IMP_TOTAL - $this->IMP_LIQUIDADO;
} */
$this->IMP_TOTAL = OOB_numeric::floatize($this->IMP_TOTAL);
$this->IMP_LIQUIDADO = OOB_numeric::floatize($this->IMP_LIQUIDADO);
$suma = $this->IMP_TOTAL + $this->IMP_LIQUIDADO;
if( $suma !=  $this->IMP_TOTAL && $this->TIPO_CBTE != 2 && $this->TIPO_CBTE != 7 )
{
// $this->IMP_NETO = $this->IMP_TOTAL - $this->IMP_LIQUIDADO;
// if($this->TIPO_CBTE != 2 && $this->TIPO_CBTE != 7 )
// {
$this->IMP_NETO = $this->IMP_TOTAL - $this->IMP_LIQUIDADO;
// } 
}
///////////////////
/////////////////////////////////convertir los montos para el caso que venga con otra moneda
  $default_currency = currency_currency::getDefault();
/* $venta_currency = false;
if($this->MONEDA != $default_currency->id())
{
$guardar_movimiento_moneda = true;
$venta_currency = new currency_currency($this->MONEDA);
}
*/
 
// $monto_total_value = OOB_numeric::floatize($this->TOTAL_VALUE);
$imp_total = OOB_numeric::floatize($this->IMP_TOTAL);
$imp_total_conceptos = OOB_numeric::floatize($this->IMP_TOTAL_CONCEPTOS);
$imp_neto = $this->IMP_NETO;
$imp_operaciones_exentas = $this->IMP_OPERACIONES_EXCENTAS;
$imp_trib = 0.00;
$imp_liquidado =  OOB_numeric::floatize($this->IMP_LIQUIDADO);
$moneda_cotizacion = $this->MONEDA_COTIZACION;
// file_put_contents ("imp_neto.txt",var_export($suma ,true));
// file_put_contents ("imp_neto.txt",var_export($imp_neto ,true));
// file_put_contents ("imp_operaciones_exentas.txt",var_export($imp_operaciones_exentas ,true));
// file_put_contents ("imp_liquidado.txt",var_export($imp_liquidado ,true));
// file_put_contents ("imp_total.txt",var_export($imp_total ,true));
$obj_moneda = new currency_value();
$obj_moneda->set('currency', currency_currency::getDefault());
$tipo_cambio = $this->MONEDA_COTIZACION;
if($this->MONEDA != $default_currency->id())
{
// $obj_moneda = new currency_value();
// $obj_moneda->set('currency', currency_currency::getDefault());
/* if($list_mov_monedas = $this->MOVIMIENTO->get('movimientos_movimiento_moneda'))
{
foreach($list_mov_monedas as $mov_moneda)
{
// $tipo_cambio = $mov_moneda->get('tipo_cambio');
$movimiento_moneda = $mov_moneda;
$obj_moneda->set('currency', $movimiento_moneda->get('moneda'));
$tipo_cambio = round(1 / $movimiento_moneda->get('tipo_cambio'),2);
break;
}
} */
$tipo_cambio = round(1 / $this->MONEDA_COTIZACION,2);
// $imp_total = 12;
$imp_total = round($this->IMP_TOTAL / $tipo_cambio,2);
$imp_total_conceptos = round($this->IMP_TOTAL_CONCEPTOS / $tipo_cambio,2);
$imp_neto = round($this->IMP_NETO / $tipo_cambio,2);
$imp_operaciones_exentas = round($this->IMP_OPERACIONES_EXCENTAS / $tipo_cambio,2);
$imp_liquidado = round($this->IMP_LIQUIDADO / $tipo_cambio,2);
}
$suma = $imp_total_conceptos+$imp_neto+$imp_operaciones_exentas +$imp_liquidado;
// file_put_contents ("imp_total.txt",var_export($imp_total ,true));

$impuestos_fe = array();
if($this->IMPUESTOS_FE)
{
$obj_iva = new StdClass();
$obj_iva->AlicIva = array();
foreach ($this->IMPUESTOS_FE as $impuesto_fe)
{
$obj_iva_elemento = new StdClass();
$obj_iva_elemento->Id = $impuesto_fe['Id'];
if($this->MONEDA != $default_currency->id())
{
$obj_iva_elemento->BaseImp =  round($impuesto_fe['BaseImp'] / $tipo_cambio,2);
$obj_iva_elemento->Importe =  round($impuesto_fe['Importe'] / $tipo_cambio,2);
}
else
{
$obj_iva_elemento->BaseImp = round($impuesto_fe['BaseImp'],2);
$obj_iva_elemento->Importe = round($impuesto_fe['Importe'],2);
}
$obj_iva->AlicIva[] = $obj_iva_elemento;
}
}
/* file_put_contents ("obj_iva.txt",var_export($obj_iva,true));
file_put_contents ("IMPUESTOS_FE.txt",var_export($this->IMPUESTOS_FE,true));
file_put_contents ("IMPUESTOS.txt",var_export($imp_total,true)); */
///////////////////////////////////////////////////////////////////////////////////////////////
//////////////////
$results_AutRequest = $client_wsfe->FECAESolicitar(
array(
'Auth' => array
(
'Token' => $this->TOKEN,
'Sign'  => $this->SIGN,
'Cuit'  => $this->CUIT_EMISOR 
),
'FeCAEReq' => array
(
'FeCabReq' => array
(
'CantReg' => $this->CANT_REGISTROS,
'PtoVta' => $this->PTO_VTA,
'CbteTipo' => $this->TIPO_CBTE //1 factura A - 6 factura B
),
'FeDetReq' => array
(
'FECAEDetRequest' => array 
(
'Concepto' => 3, // Productos y servicios
'DocTipo' => $this->TIPO_DOC , //80 (CUIT)
'DocNro' => floatval($this->NUM_DOC),
'CbteDesde' => $this->LastCBTE + 1,
'CbteHasta' => $this->LastCBTE + 1,
'CbteFch' => date('Ymd'),
'ImpTotal' => round($imp_total,2),
'ImpTotConc' => round($imp_total_conceptos,2),
'ImpNeto' => round($imp_neto,2),
'ImpOpEx' => round($imp_operaciones_exentas,2),
'ImpTrib' => 0.00,
'ImpIVA' => round($imp_liquidado,2),
'FchServDesde' =>  date('Ymd'),
'FchVtoPago' =>  date('Ymd'),
'FchServHasta' =>  date('Ymd'),
// 'MonId' => 'PES',
'MonId' => $this->MONEDA_AFIP,
// 'MonCotiz' => 1,
'MonCotiz' => $tipo_cambio,
'Iva' => $obj_iva
)
),
)
));
                   
    file_put_contents( microtime(true)  . '_results_AutRequest.txt',var_export($results_AutRequest,true));
    file_put_contents( microtime(true)  . '_results_AutRequest_soap.txt',var_export($client_wsfe,true));


// if ( $results_AutRequest->FEAutRequestResult->RError->percode != 0 )
if ( isset($results_AutRequest->FECAESolicitarResult->Errors) )
    {        
$this->error()->addError('NO_CAE',true);
$this->error()->addError( var_export($results_AutRequest,true),true );
    }
else
{  
// $detalle_response = $results_AutRequest->FEAutRequestResult->FedResp->FEDetalleResponse;
$detalle_response = $results_AutRequest->FECAESolicitarResult->FeDetResp->FECAEDetResponse;
$resultado = (string)$results_AutRequest->FECAESolicitarResult->FeCabResp->Resultado;
if ($resultado != 'A')
{
$this->error()->addError('NO_CAE',true);
$this->error()->addError( var_export($results_AutRequest,true),true ); 
}
$this->XML = htmlspecialchars( $client_wsfe->__getLastResponse() );
// file_put_contents('results_AutRequest.txt',var_export($this->XML,true));
if( $detalle_response ){
// $this->CAE = $detalle_response->cae;
$this->CAE = $detalle_response->CAE;
// $this->VTO_CAE = $detalle_response->fecha_vto;
$this->VTO_CAE = $detalle_response->CAEFchVto;
$this->NUMERO_COMPROBANTE = str_pad( ($this->LastCBTE + 1), 8, "0", STR_PAD_LEFT ) ;
$this->NUMERO_COMPROBANTE = str_pad( ($this->LastCBTE + 1), 8, "0", STR_PAD_LEFT ) ;
}
}
///////////////////////////////////////////////

--

Diego Scifo

unread,
Aug 11, 2015, 7:29:14 AM8/11/15
to Grupo PHP Argentina
Pablo,

Muchas gracias por tu respuesta.

Será mucho pedir que me pases los paths (para usar de referencia) del certificado y la llave privada que se utiliza en la función openssl_pkcs7_sign(...) no puedo dar con la estructura correcta ya que me devuelve el siguiente warning; openssl_pkcs7_sign() error getting private key. Por lo que estuve investigando se debe a como se debe acceder al archivo de la clave privada.

Gracias de antemano.

Saludos.

Kano Kanito

unread,
Aug 13, 2015, 1:11:19 PM8/13/15
to Grupo PHP Argentina

tengo el mismo problema y no lo puedo solucionar.

Pablo Micolini

unread,
Aug 23, 2015, 7:32:10 PM8/23/15
to php...@googlegroups.com
Para que quede en el historial, estos son los datos:

cert, privatekey y passphrase 
son 3 strings, que deben ser rellenados con los datos de los certificados y las claves, en el caso del cert, por ejemplo usando file_get_contents.

en $this->WSDL_WSAA , va la ruta al archivo del wsdl

$directory =  "afip" . DIRECTORY_SEPARATOR . $id_cliente.  DIRECTORY_SEPARATOR;
if (!is_dir ($directory))
{
if (!mkdir ($directory, '0777', true))
{
$ari->error->addError('LOG-ACTION','No se pudo crear el directorio de afip para ' . $id_cliente,true);
}
}

$this->AFIP_DIR = $directory;
$this->TRA_DIR = "{$this->AFIP_DIR}TRA.xml"; //direccion en donde se guarda el xml del ticket de requerimiento de acceso
$this->TMP_TRA_DIR = "{$this->AFIP_DIR}TRA.tmp"; //archivo temp para el TRA
$this->TA = "{$this->AFIP_DIR}TA.xml";


Saludos!

Tordek

unread,
Aug 23, 2015, 8:30:24 PM8/23/15
to php...@googlegroups.com
> en el caso del cert, por ejemplo usando file_get_contents.

No hace falta. Podés poner, como en el ejemplo si leés la documentación en la página de PHP, "file://certificado.crt".

Estoy armando una biblioteca para acceder a WSAA/WSFE; estoy terminando unos detalles que faltan para poder hacer facturas C (porque son las que necesitaba, y es para tener una base para empezar a agregar features), y en estos días libero lo que tengo hecho.
Reply all
Reply to author
Forward
0 new messages