/*
+-----------------+------------------------------------------------------------+
| FUNCION         | search_timeout                                             |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Busca un timeout en la cola                                |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
void search_timeout()
{
    int	   cont;
    int	   ret;
	char   aux_str1[100];		
    
    /* Loguea la hora */
	LogAlarm.Put(0, "search_TO(): Revisando TO...%s",  currentTimeLog());
    
    /* Busca un time out */
    cont=timeout_queue.FindTO();
    if (cont > -1)
    {
        /* Procesa un time out */ 
		process_timeout(cont);
    }
	else
	{
		/* Espera para siguiente ejecucion */
		LogAlarm.Put(0, "search_TO(): Esperando...\n");
		Cfg.GetItem("TimeOutDaemon", "SleepTime", aux_str1);
		sleep(atoi(aux_str1));
		LogAlarm.Put(0, "search_timeout(): Listo.\n");
	}
}
Beispiel #2
0
/*
+-----------------+------------------------------------------------------------+
| FUENTE          | Pos::SetPosBusy                                            |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Agrega una caja a la lista de ocupadas                     |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int Pos::SetPosBusy(char *ca, char *suc, char *caj)
{
    int	cont=0;

    /* Busca el siguiente disponible */
    while ((pos[cont].nro_ca[0]!='\0') && (cont<POS_MAX_MEMBERS))
	{
		cont++;
    }

	/* Si hay una posicion libre */
	if (pos[cont].nro_ca[0]=='\0')
    {
		/* Agrega el elemento */
		strcpy(pos[cont].nro_ca  , ca);
		strcpy(pos[cont].nro_caj , caj);
		strcpy(pos[cont].nro_suc , suc);
		LogAlarm.Put(5, "Objeto Pos: SetPosBusy [%s%s%s]. Posicion [%d]\n", ca, suc, caj, cont );

		/* Retorna el resultado OK */
		Errno=OK;
		return OK;
    }
	else
	{
		LogAlarm.Put(5, "Objeto Pos: SetPosBusy [%s%s%s]. NO HAY POSICIONES LIBRES\n", ca, suc, caj );
	}

	/* Retorna el resultado error */
    Errno=ENOSPC;
    return NOOK;
}
Beispiel #3
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | PriceOnLine::Armar_y_Enviar_Respuesta                      |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Arma un mensaje de respuesta local en funcion del mensaje  |
|                 | recibido y datos calculados y lo envia al TPV              | 
+-----------------+------------------------------------------------------------+
*/
int PriceOnLine::Armar_y_Enviar_Respuesta(char *szCodRta, struct trxRtaTPV *stRta)
{
	Price_Msg		*priceRta;
	char			szCampo13[LON_CAMPO_13 + 1];
	char			szMsgStr[2000];
	int				iLen;
	int				iRet = 0;
	char			szCpoTerVer[25+1];

	/* Arma mensaje de respuesta de rechazo hacia el TPV por configuracion erronea */
	priceRta=new Price_Msg(TYPE_PRICE_VENTA_RTA);
	
	/* Completa campos de la respuesta */
	priceRta->PutField( 1, mensaje_price->GetField( 1));
	priceRta->PutField( 2, mensaje_price->GetField(15));
	priceRta->PutField( 3, mensaje_price->GetField(16));
	priceRta->PutField( 4, mensaje_price->GetField(11));
	priceRta->PutField( 7, mensaje_price->GetField( 4));
	priceRta->PutField( 8, mensaje_price->GetField( 5));
	priceRta->PutField( 9, stRta->szCodAut);
	priceRta->PutField(10, "");
	priceRta->PutField(11, stRta->szComerc);
	priceRta->PutField(15, mensaje_price->GetCodTar());
	priceRta->PutField(16, "000000000000");
	sprintf(szCampo13, "%03d%1s%8s%s%s ", atoi(stRta->szNroLot), FLAG_OFFLINE, PINPAD_NULO, stRta->szRespCA, stRta->szPlanSF); 
	priceRta->PutField(13, szCampo13);
	priceRta->PutField( 6, szCodRta); 

	/* Devuelve nro de terminal y version */
	sprintf(szCpoTerVer, FTO_VER, stRta->szTermin, stRta->szProtoc, stRta->szPlnIso, 
								  NO_ANUL, VERSION_NRO, stRta->szTicOri, stRta->szFecOri );
	priceRta->PutField(12, szCpoTerVer);

	/* Aplana el mensaje */
	iLen = priceRta->GetMsgString(szMsgStr);

	/* Borra el mensaje price */
	delete priceRta;

	/* Envia respuesta al TPV */
	iRet = SQueue.SendMsg(orig_pid, szMsgStr, iLen);
	if (iRet != OK)
	{
		LogAlarm.Put(0, "PriceOn: ERROR (%d) al enviar respuesta\n", SQueue.GetErrno());
	}	
	else
	{
		LogAlarm.Put(0, "PriceOn: RESPUESTA LOCAL: %s\n", szCodRta);
	}
	return (iRet);
}
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | RtaRevAnul::ProcessIt                                      |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Proceso del objeto                                         |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int RtaRevAnul::ProcessIt()
{
	int              len;
	int              ret;
	str_sel_cadata   term_data;
	trxAnulHeap	     heap_data;
	char             msgrta[300];	
	char			 idHeap[20];
	char			 aux_str1[100];
	int				 iCont;
	Queue 			 EQueue;	
	trxRevHeap		 heap_reve;

	/* Obtiene los datos de la caja en funcion de la caja del centro autorizador */
	strcpy(term_data.nro_caj_ca, IsoMsg->GetField(41)); 
	ret=ObtCaCaj(&term_data);
	if (ret!=OK)
	{
		/* Loguea el mensaje en caso de error */
		LogAlarm.Put(0, "RtaRevAnul: ERROR (%d) al obtener datos de la caja [%s]\n", ret, term_data.nro_caj_ca);
		return NOOK;
	}

	/* Obtiene los datos del heap */
	sprintf(idHeap,"%2.2s%3.3s%5.5s%8.8s", term_data.nro_ca, term_data.nro_suc, term_data.nro_caj, IsoMsg->GetField(11));
	LogAlarm.Put(0, "RtaRevAnul: Extrayendo datos del heap [%s]\n", idHeap);
	ret=Heap.GetData(idHeap,(char *)&heap_reve, sizeof(heap_reve));
	if (ret==NOOK)
	{
		LogAlarm.Put(0, "RtaRevAnul: Transaccion no existe en Heap [%s]\n", idHeap);
		return NOOK;
	}
	else
	{
		LogAlarm.Put(0, "RtaRevAnul: Reenvio a RevTrxRta\n");
		Cfg.GetItem("VisaDaemon", "QueueID", aux_str1);
		if ( EQueue.Open(atoi(aux_str1)) == OK )
		{
			Heap.PutData(idHeap,(char *)&heap_reve, sizeof(heap_reve));
			EQueue.SendMsg(EVENT_SNDREVERSO_RTA, szMsjeISO, iLMsjeISO);
		}		
	}
	LogAlarm.Put(0, "RtaRevAnul: Evento finalizado\n");	
	return OK;
}
Beispiel #5
0
/*
+-----------------+------------------------------------------------------------+
| FUENTE          | Pos::SetPosFree                                            |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Elimina una caja de la lista de ocupadas                   |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int Pos::SetPosFree(char *ca, char *suc, char *caj)
{
    int	cont=0;
    
	/* Busca la clave */   
    while ( ( (strcmp(pos[cont].nro_ca , ca )) || 
              (strcmp(pos[cont].nro_caj, caj)) ||
			  (strcmp(pos[cont].nro_suc, suc)) 
			) && (cont<POS_MAX_MEMBERS) )
    {
		cont++;
    }
    
	/* Si encuentra la clave */
	if ( (strcmp(pos[cont].nro_ca  , ca )==0) &&
		 (strcmp(pos[cont].nro_caj , caj)==0) &&
		 (strcmp(pos[cont].nro_suc , suc)==0) )
    {
		LogAlarm.Put(5, "Objeto Pos: SetPosFree [%s%s%s]. Posicion [%d]\n", ca, suc, caj, cont);

		/* Libera el elemento */
		pos[cont].nro_ca[0]  = '\0';
		pos[cont].nro_caj[0] = '\0';
		pos[cont].nro_suc[0] = '\0';
		
		/* Retorna el resultado OK */
		Errno=OK;
		return OK;
    }
	else
	{
		LogAlarm.Put(5, "Objeto Pos: SetPosFree [%s%s%s]. Posicion no encontrada\n", ca, suc, caj);
	}

	/* Retorna el resultado error */
    Errno=ENOENT;
    return NOOK;  
}
Beispiel #6
0
/*
+-----------------+------------------------------------------------------------+
| FUENTE          | Pos::IsPosFree                                             |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Verifica si una caja esta libre                            |
|                 | Retorna: 1:No encontrado - 0:Encontrado                    | 
+-----------------+------------------------------------------------------------+
*/
int Pos::IsPosFree(char *ca, char *suc, char *caj)
{
    int	cont=0;
    int ret;

    /* Busca si la clave se encuentra */
    while ( ( (strcmp(pos[cont].nro_ca  , ca )) || 
              (strcmp(pos[cont].nro_caj , caj)) ||
              (strcmp(pos[cont].nro_suc , suc)) 
			) && (cont<POS_MAX_MEMBERS) )
	{
        cont++;
    }
    
	/* Retorna el resultado */
	ret = (cont==POS_MAX_MEMBERS);

	LogAlarm.Put(5, "Objeto Pos: IsPosFree  [%s%s%s]. Retorno [%d]\n", ca, suc, caj, ret);

    return ret;
}
Beispiel #7
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | EchoTest::EnviarMsg                                        |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Envia un mensaje por la cola administrativa                |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int EchoTest::EnviarMsg(int orig_pid, char *msg, int len)
{
	Queue AQueue;
	int iRet;
	char msgString[500];
	char auxString1[100];

	/* Abre cola de mensajes administrativos */
	Cfg.GetItem("AdminDaemon", "QueueID", auxString1);
	iRet = AQueue.Open(atol(auxString1));
	if (iRet==OK)
	{
		/* Envia mensaje */
		memset(msgString, 0, sizeof(msgString));
		memcpy(msgString, msg, len);
		iRet = AQueue.SendMsg(orig_pid, msgString, len);
	}
	if (iRet)
	{
		LogAlarm.Put(0, "EchoTest: ERROR al enviar mensaje por cola administrativa\n");
	}
	return iRet;
}
Beispiel #8
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | EchoTest::ProcessIt                                        |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Proceso del objeto                                         |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int EchoTest::ProcessIt()
{
	char	msg_str[2000];
	int		len;
	int		ret;
	int		HeapOcup = 0;
	int		TOQueueOcup = 0;
	char	aux_str1[100];	
	char	idHeap[20];
	str_sel_cadata	term_data;
	int     iCantidad;

	/* Arma los datos de la terminal */
	memset(&term_data, 0, sizeof(term_data));
	strncpy(term_data.nro_suc, ping_data.nro_suc, sizeof(term_data.nro_suc));
	strncpy(term_data.nro_caj, ping_data.nro_caj, sizeof(term_data.nro_caj));
	strncpy(term_data.nro_ca , ping_data.nro_ca , sizeof(term_data.nro_ca ));
	LogAlarm.Put(0, "EchoTest: Suc:[%s] Caj:[%s] CA:[%s]\n", term_data.nro_suc, term_data.nro_caj, term_data.nro_ca);

	/* Obtiene datos de la terminal */
	ret=getDataByNTET(&term_data);
	if (ret!=OK)
	{
		LogAlarm.Put( 1, "EchoTest: ERROR (%d) al obtener datos de la terminal\n", ret);
		EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}

	/* Se carga en el objeto TraceNmbr el centro autorizador con el que se trabaja */
	TraceNumber.SetNroSuc(term_data.nro_suc);
	TraceNumber.SetNroCaj(term_data.nro_caj);
	TraceNumber.SetNroCA (term_data.nro_ca );
	TraceNumber.SetCodConCie("0");

	/* Arma mensaje iso */
	mensaje_iso->PutField(7, currentTimestamp());
	strcpy(aux_str1, TraceNumber);
	TraceNumber.Inc();
	mensaje_iso->PutField(11, aux_str1); 
	mensaje_iso->PutField(24, term_data.cod_red);
	mensaje_iso->PutField(41, term_data.nro_caj_ca);
	mensaje_iso->PutField(42, term_data.nro_com_et);

	/* Arma clave del heap */
	sprintf(idHeap,"%02d",atoi(term_data.nro_ca));

	/* Verifica si se encuentra en el heap */
	LogAlarm.Put(0, "EchoTest: Busca clave en el heap [%s]\n", idHeap);
	ret=Heap.FindData(idHeap, (char *)&orig_pid,sizeof(orig_pid));
	if (ret!=1)
	{
		LogAlarm.Put(0, "EchoTest: Heap ocupado. Clave:[%s]\n", idHeap);
		HeapOcup = 1;
	}
	LogAlarm.Put(0, "EchoTest: Valor de HeapOcup %d\n", HeapOcup);

	/* Verifica si se encuentra en la TOQ */
	ret=timeout_queue.FindTimeOut(idHeap);
	if (ret==1)
	{
		LogAlarm.Put(0, "EchoTest: Se encontro en TOQueue. Clave:[%s]\n", idHeap);
		TOQueueOcup = 1;
	}
	LogAlarm.Put(0, "EchoTest: Valor de TOQueueOcup %d\n", TOQueueOcup);

	/* Si el ping esta activo */
	if ((HeapOcup == 1) && (TOQueueOcup == 1))
	{
		/* Envia respuesta por la cola administrativa */
		LogAlarm.Put(0, "EchoTest: Ping Activo. Esta ocupado\n");
		LogAlarm.Put(0, "EchoTest: Envia respuesta por la cola administrativa\n");
		ret= EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}
	else 
	{
		/* Si el head esta ocupado */
		if (HeapOcup == 1)
		{
			LogAlarm.Put( 0, "EchoTest: Se encuentra en Heap pero no en TOQ\n");
			ret=Heap.GetData(idHeap, (char *)&orig_pid,sizeof(orig_pid));
			if (ret==NOOK)
			{
				LogAlarm.Put( 0, "EchoTest: ERROR (%d) al extraer de heap\n", Heap.GetErrno());
				EnviarMsg(orig_pid, "ERROR", 5);			
				return NOOK;
			}
		}

		/* Si la TOQ esta ocupada */ 
		if (TOQueueOcup == 1) 
		{
			LogAlarm.Put( 0, "EchoTest: Se encuentra en TOQ pero no en Heap\n");
			ret=timeout_queue.RemTimeOut(idHeap);
			if (ret==NOOK)
			{
				LogAlarm.Put(0, "EchoTest: ERROR (%d) al extraer de TOQ\n", timeout_queue.GetErrno());
				EnviarMsg(orig_pid, "ERROR", 5);
				return NOOK;
			}
		}
	}

	/* Registra en el heap */
	LogAlarm.Put(0, "EchoTest: Registra mensaje en el heap.\n");
	ret=Heap.PutData(idHeap, (char *)&orig_pid,sizeof(orig_pid));
	if (ret==NOOK)
	{
		LogAlarm.Put(0, "EchoTest: ERROR (%d) al registrar en el heap\n", Heap.GetErrno());
		EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}

	/* Registra en la TimeoutQueue	*/
	LogAlarm.Put(0, "EchoTest: Registra mensaje en la TOQ\n");
	Cfg.GetItem("TimeOutDaemon", "MsgTimeOut1", aux_str1);
	ret=timeout_queue.SetTimeOut(idHeap, atoi(aux_str1), GetType(), "");
	if (ret==NOOK)
	{
		LogAlarm.Put(0, "EchoTest: ERROR (%d) al agregar a la TOQ\n", timeout_queue.GetErrno());

		/* Retira del heap si hubo error */
		ret=Heap.GetData(idHeap, (char *)&orig_pid,sizeof(orig_pid));
		if (ret==NOOK)
		{
			LogAlarm.Put( 0, "EchoTest: ERROR (%d) al obtener del heap\n", Heap.GetErrno());
		}
		EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}

	/* Aplana el mensaje */
	len=mensaje_iso->GetMsgString(msg_str);

	/* Envia por la cola de X.25 */
	LogAlarm.Put(0, "EchoTest: Envia a X.25. CAut [%s]\n", term_data.nro_ca);
	ret=XQueue.SendMsg(atoi(term_data.nro_ca)+1, msg_str, len);
	if (ret!=OK)
	{
		LogAlarm.Put( 0, "EchoTest: ERROR (%d) al enviar por X.25!!\n", XQueue.GetErrno());
		EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}
	return OK;
}
Beispiel #9
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | Batch::ProcessIt                                           |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Proceso del objeto                                         |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int Batch::ProcessIt()
{
    char			aux_str[100];
    char			msg_str[2000];
    int				msg_len;
    int				ret;
    str_heap_data	heap_data;
    str_sel_ntdata	term_data;
    char			idHeap[20];

    /* Obtiene los datos del mensaje */
    LogAlarm.Put(5, "Batch: Obteniendo datos de la terminal.\n");
    strcpy(term_data.nro_caj_ca, mensaje_iso->GetField(41));
    strcpy(term_data.nro_com   , mensaje_iso->GetField(42));

    /* Obtiene datos de la terminal */
	ret=getDataByCA(&term_data);
	if (ret!=OK)
	{
		LogAlarm.Put( 0, "Batch: ERROR (%d) al obtener datos de la terminal\n", ret);
		return NOOK;
	}

    /* Se indica al objeto TraceNmbr con que centro autorizador se trabaja */
    TraceNumber.SetNroSuc(term_data.nro_suc);
    TraceNumber.SetNroCaj(term_data.nro_caj);
    TraceNumber.SetNroCA (term_data.nro_ca );
    TraceNumber.SetCodConCie(term_data.cod_con_cie);

	/* Setea centro autorizador */
	mensaje_iso->SetNroCA8583(term_data.nro_ca);
	
	/* Obtiene tarjeta y la carga para agregar 'F' final */
	switch (DBTipoProtocoloISO(term_data.nro_ca))
	{
	case PROT_ISO_AMEX:
		sprintf(aux_str, "%s", mensaje_iso->GetField(2));
		mensaje_iso->PutField(2, aux_str);
		break;
	default:
		break;
	}
	
    /* Completar el mensaje con los datos generados	*/
    strcpy(aux_str, TraceNumber);
    TraceNumber.Inc();
    mensaje_iso->PutField(11, aux_str); 

    /* Chequea consistencia del mensaje	*/
    LogAlarm.Put(5, "Batch: Checkeo de consistencia del msg.\n");
    if (!mensaje_iso->ChkReady())
	{
		LogAlarm.Put(0,"Batch: ERROR mensaje ISO incompleto\n");
		return NOOK;
	}

    /* Registra transaccion en TrxHeap	*/
    LogAlarm.Put(5, "Batch: Obteniendo datos para el Heap.\n");
    heap_data.orig_pid=orig_pid;
    LogAlarm.Put(5, "Batch: Poniendo datos en el Heap.\n");
    sprintf(idHeap,"%2.2s%3.3s%5.5s%8.8s", term_data.nro_ca, term_data.nro_suc,
                                           term_data.nro_caj, mensaje_iso->GetField(11));
    ret=Heap.PutData(idHeap,(char *)&heap_data, sizeof(heap_data));
    if (ret==NOOK)
	{
		LogAlarm.Put(5, "Batch: ERROR (%d) al agregar en el Heap\n", Heap.GetErrno());
		return NOOK;
	}

    /* Registra en la TimeoutQueue	*/
    LogAlarm.Put(5, "Batch: Agregando a la TO Queue.\n");
    Cfg.GetItem("TimeOutDaemon", "MsgTimeOut320", aux_str);
    ret=timeout_queue.SetTimeOut(idHeap, atoi(aux_str), GetType(), "");
	if (ret==NOOK)
	{
		LogAlarm.Put(0, "Batch: ERROR (%d) al agregar en TimeOutQueue\n", timeout_queue.GetErrno());
		return NOOK;
	}

	/* Aplana el mensaje */
    msg_len=mensaje_iso->GetMsgString(msg_str);

    /* Envia el mensaje por X25 */
    LogAlarm.Put(0, "Batch: Envia a X.25. CAut [%s]\n", term_data.nro_ca);
	ret=XQueue.SendMsg(atoi(term_data.nro_ca)+1, msg_str, msg_len);
    if (ret==NOOK)
	{
		LogAlarm.Put(0, "Batch: ERROR (%d) al enviar a Cola X.25\n", XQueue.GetErrno());
		return NOOK;
	}
	LogAlarm.Put(5, "Batch: Evento finalizado\n");

    return OK;
}
Beispiel #10
0
main()
{
   Log		LogAlarm;
   Config	CfgCred("credito.ini");
   char		buffer1[500];
   char		buffer2[500];
   Queue	XQueue,EQueue;
   long		QueueID,QueuePerm;
   struct	tm *newtime;
   time_t	ltime;
   int 		ret;
   int 		len;
   Iso_Msg	*IsoMsg;
   Iso_Msg	*IsoRta;

   LogAlarm.Open("../log/Em.log");
   LogAlarm.SetLevel(10);

   CfgCred.GetItem("CAVisaDaemon","QueueID",buffer1);
   QueueID=atol(buffer1);
   CfgCred.GetItem("CAVisaDaemon","QueuePerms",buffer2);
   QueuePerm=atol(buffer2);
   ret=XQueue.Create(QueueID,QueuePerm);

   if (ret!=OK)
      exit(ret); 

   CfgCred.GetItem("Daemon","QueueID",buffer1);
   QueueID=atol(buffer1);
   CfgCred.GetItem("Daemon","QueuePerms",buffer2);
   QueuePerm=atol(buffer2);
   ret=EQueue.Open(QueueID,QueuePerm);
   if (ret!=OK)
   { 
      exit(ret); 
   }
   
   time(&ltime); 
   newtime=localtime(&ltime);
   srandom(newtime->tm_sec);
   LogAlarm.Put(1,"Comenzando Operacion %s\n",asctime(newtime)); 

   while (ret==OK)
   {
	len=XQueue.GetMsg(0, buffer1, sizeof(buffer1));
	if (len==NOOK)
	{
	   break;
	}

	IsoMsg=new Iso_Msg(buffer1,len);

	switch (IsoMsg->GetMsgType())
	{
	   case TYPE_VISA_VENTA:
	       LogAlarm.Put(1,"Recibido PriceOn [%s] [%s]\n",
		      IsoMsg->GetField(41),IsoMsg->GetField(11));
	       IsoRta = new Iso_Msg(TYPE_VISA_VENTA_RTA);
	       IsoRta->PutField(2,IsoMsg->GetField(2));
	       IsoRta->PutField(11, IsoMsg->GetField(11));
	       IsoRta->PutField(24, IsoMsg->GetField(24));

	       sprintf(buffer1,"%012%d",random());
	       IsoRta->PutField(37,buffer1);

	       sprintf(buffer1,"%06d",random());
	       IsoRta->PutField(38,buffer1);

	       IsoRta->PutField(39,"00");
	       IsoRta->PutField(41, IsoMsg->GetField(41));

	       len=IsoRta->GetMsgString(buffer1);

	       ret=EQueue.SendMsg(EVENT_PRICEONLINE_RTA,buffer1,len);

               break;
        }

   }
}
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | init                                                       |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Inicia las estructuras y memoria compartida                |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int init()
{
    int	ret;
    int	cont;
	int	max_entries;
	char aux_str1[100];
	char aux_str2[100];

    /* Configura las señales de terminacion */
	signal(SIGINT, shut_down);
    signal(SIGTERM, shut_down);

    /* Obtiene el nombre del archivo de log */
	Cfg.GetItem("TimeOutDaemon", "LogName", aux_str1);
    LogAlarm.Open(aux_str1);

    /* Setea el nivel de log */
	Cfg.GetItem("TimeOutDaemon", "LogLevel", aux_str1);
    LogAlarm.SetLevel(atoi(aux_str1));

	/* Loguea hora de comienzo */
    LogAlarm.Put( 0,"TimeOutDaemon::init(): Comienzo [%s] - %s", NUM_VERSION, currentTimeLog()); 

    /* Obtiene la cantidad maxima de entradas en la cola */
	Cfg.GetItem("TimeOutDaemon", "MaxEntries", aux_str1);
    max_entries=atoi(aux_str1);

    /* Obtiene la cantidad maxima de entradas en la tabla de PIDs */
	Cfg.GetItem("PIDTable", "ShMemID", aux_str1);
    Cfg.GetItem("PIDTable", "MaxEntries", aux_str2);

    /* Abre tabla de PIDs */
	LogAlarm.Put(0, "TimeOutDaemon::init(): Abre tabla de PIDs [%s] [%s]\n", aux_str1, aux_str2);
    while (PTable.Open(atoi(aux_str1), atoi(aux_str2))==NOOK)
    {
		if (PTable.GetErrno()!=ENOENT)
		{
			LogAlarm.Put(0, "TimeOutDaemon::init(): Error (%d)!!\n", PTable.GetErrno());
			exit(1);
		}
    }
    
	/* Pone el pid en la tabla */
	LogAlarm.Put(0, "TimeOutDaemon::init(): Adding PID to PID table...\n");
    ret=PTable.PutPid(getpid());
    if (ret==NOOK)
    {
		LogAlarm.Put(0, "TimeOutDaemon::init(): Error (%d)!!\n", PTable.GetErrno());
		exit(1);
    }

    /* Obtiene los identificadores y permisos de la cola de timeout */
	Cfg.GetItem("TimeOutDaemon", "ShMemID", aux_str1);
    Cfg.GetItem("TimeOutDaemon", "ShMemPerms", aux_str2);

    /* Crea cola de timeout */
    LogAlarm.Put(0, "TimeOutDaemon::init(): Creando area de memoria compartida para la Timeout_Queue\n");  
    ret=timeout_queue.Create(atoi(aux_str1), max_entries, atoi(aux_str2));
    if (ret==NOOK)
    {
		LogAlarm.Put(0, "TimeOutDaemon::init(): Error (%d) al crear area para la Timeout_Queue \n", timeout_queue.GetErrno());
    }

    /* Obtiene identificador de la cola de eventos */
	Cfg.GetItem("VisaDaemon", "QueueID", aux_str1);
    
	/* Abre cola de eventos */
	LogAlarm.Put(0, "TimeOutDaemon::init(): Abriendo cola de eventos...\n");
    ret= EQueue.Open(atoi(aux_str1));
    if (ret==NOOK)
	{
		LogAlarm.Put(1, "TimeOutDaemon::init(): Error (%d) al abrir cola de eventos!!\n", EQueue.GetErrno());
		return NOOK;
	}

    return OK;
}
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | process_timeout                                            |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Procesa el timeout.                                        |
|                 | Parametro: cont: Posicion de la cola con el timeout        | 
+-----------------+------------------------------------------------------------+
*/
void process_timeout(int cont)
{
	int		ret;
	int		event_type;
	str_timeout     	*timeout_data;
	str_timeout_event	timeout_event_data;
	char	aux_str1[100];	
	
	/* Obtiene los datos del elemento con time out vencido */
	timeout_data=timeout_queue.GetTimeOut(cont);
	LogAlarm.Put(0, "process_timeout(): Se encontro un TO (id:%s)\n", timeout_data->id);
	
	/* Si expired==0 */
	if (timeout_data->expired==0)
	{
		/* Setea el primer timeout */
		Cfg.GetItem("TimeOutDaemon", "MsgTimeOut2", aux_str1);
		LogAlarm.Put(0, "process_timeout(): Primer timeout\n");
		timeout_queue.SetOne(cont, atoi(aux_str1)); 
		
		/* Generar evento TimeOut */
		LogAlarm.Put(0, "process_timeout(): Generando evento TimeOut...\n");
		
		/* Completa la estructura del timeout */
		strcpy(timeout_event_data.key,timeout_data->id);
		strcpy(timeout_event_data.cod_ser,timeout_data->cod_ser);
		
		/* Obtiene el tipo de evento */
		switch (timeout_data->event_type)
		{
		case EVENT_REVTRXANUL:
			LogAlarm.Put(5,"process_timeout():  generando TimeOut de Reverso Anulacion \n");
			event_type=EVENT_TIMEOUT_REV_ANUL;
			break;
		case EVENT_SNDTRXANUL:
			LogAlarm.Put(5,"process_timeout():  Generando Timeout de Anulacion \n");
			event_type=EVENT_TIMEOUT_ANULACION;
			break;
		case EVENT_CIERRE:
			LogAlarm.Put(5, "process_timeout(): Generando TimeOut de cierre...\n");
			event_type=EVENT_TIMEOUT_CIERRE;
			break;
		case EVENT_CIERRE_B:
			LogAlarm.Put(5, "process_timeout(): Generando Timeout de cierre Batch\n");
			event_type=EVENT_TIMEOUT_CIERRE_B;
			break;
		case EVENT_BATCH:
			LogAlarm.Put(5, "process_timeout(): Generando Timeout en trx de batch upload\n");
			event_type=EVENT_TIMEOUT_BATCH;
			break;
		case EVENT_SNDTRXOFFLINE:
			LogAlarm.Put(5, "process_timeout(): Generando Timeout de Transaccion offline\n");
			event_type=EVENT_TMTTRXOFFLINE;
			break;
		case EVENT_SNDREVERSO:
			LogAlarm.Put(5, "process_timeout(): Generando Timeout de reverso\n");
			event_type=EVENT_TIMEOUT_REVERSO;
			break;
		case EVENT_ECHOTEST:
			LogAlarm.Put(5, "process_timeout(): Generando Timeout de echo test\n");
			
			event_type=EVENT_TIMEOUT_ECHOTEST;
			break;
		default:
			LogAlarm.Put(5, "process_timeout(): Generando Timeout generico\n");
			event_type=EVENT_TIMEOUT;
		}
		
		/* Envia el mensaje al Daemon */
		ret=EQueue.SendMsg(event_type, (char *)&timeout_event_data, sizeof(str_timeout_event));
		if (ret==NOOK)
		{
			LogAlarm.Put(5, "process_timeout: Error (%d) en Envio de Evento Timeout!!\n", EQueue.GetErrno());
		}
	}
	else  /* expired en 1 (ya se habia cumplido el 1er. timeout) */
	{
		/* Borra el timeout de la cola */
		LogAlarm.Put(0, "process_timeout: Segundo timeout. Borrando de la tabla...\n");
		timeout_queue.SetSecond(cont);
	}
}
Beispiel #13
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | PriceOnLine::ProcessIt                                     |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Proceso del objeto                                         |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int PriceOnLine::ProcessIt()
{
	str_sel_cadata	term_data;
	str_heap_data	heap_data;
	TrxData			trx_data;
	char			msg_str[2000];
	char			aux_str[64];
	char			szNroCta[64];
	int				cont;
	int				len;
	int				ret;
	int				limite=OK;
	int				channel_down;
	int				pos_ocup;
	int				TrxEnVuelo;
	str_upd_rev		StrDataRev;
	char 			CajDevol[6];
	char 			TrxDevol[5];
	char 			CajVenta[6];
	char 			TrxVenta[5];
	char			FecVenta[7];
	char			szCampo13[LON_CAMPO_13 + 1];
	char			szCuotas[32];
	/* Modificacion PINPAD */
	char			szPinPad[64];
	int				iHayPinPad;
	/* Pinpad 2*/
	long			lCodProc;
	long			lCodCuenta;
	char			szCodiProc[16];
	int				iTipoOperacion=0;
	char			NroTrxAux[9];
	char			szRowId[64];
	char			szFHtransm[32];
	char			szFHoperac[32];
	long			lImpoTran;
	long			lCashBack;
        char                    szCriptograma[1024] = {0};
        char                    szVersionEMV[20] = {0};
        char                    szEMVProductList[512] = {0};
	struct trxRtaTPV stRta;
	
	/* Blanquea estructura de respuesta */
	memset(&stRta, 0, sizeof(stRta));
	memset(stRta.szCodAut, ' ', sizeof(stRta.szCodAut)-1);
	memset(stRta.szComerc, ' ', sizeof(stRta.szComerc)-1);
	memset(stRta.szTermin, ' ', sizeof(stRta.szTermin)-1);
	memset(stRta.szNroLot, ' ', sizeof(stRta.szNroLot)-1);
	memset(stRta.szPlnIso, ' ', sizeof(stRta.szPlnIso)-1);
	memset(stRta.szProtoc, ' ', sizeof(stRta.szProtoc)-1);
	memset(stRta.szRespCA, ' ', sizeof(stRta.szRespCA)-1);
	memset(stRta.szFecOri, ' ', sizeof(stRta.szFecOri)-1);
	memset(stRta.szTicOri, ' ', sizeof(stRta.szTicOri)-1);
	memset(stRta.szPlanSF, ' ', sizeof(stRta.szPlanSF)-1);
        

	/* Track II en las IBM no viene el separador de campos '='. Se agrega */
	char TrackIIprice[40];
	char * indexTr;
	strcpy(TrackIIprice,mensaje_price->GetField(10));
	if ((indexTr=strchr(TrackIIprice,'D'))!=NULL)
	{
		*indexTr='='; 
		mensaje_price->PutField(10,TrackIIprice);
	}
	
	/* Se invierte la fecha de caducidad siempre */
	mensaje_price->InvertirFecha(); 
	
	/* Se loguean los datos de la terminal */
	LogAlarm.Put(0, "PriceOn: Emp:[%s] Suc:[%s] Ter:[%s] Trx:[%s] Tar:[%s] Plan:[%s]\n", 
						mensaje_price->GetEmpresa()     , 
						mensaje_price->GetSucursal()    ,
						mensaje_price->GetTerminal()    ,
						mensaje_price->GetTransaccion() ,
						mensaje_price->GetCodTar()      ,
						mensaje_price->ObtPlanSf());

	/* Se obtienen los datos de la terminal en base al mensaje price */
	strcpy(term_data.plan_sf, mensaje_price->ObtPlanSf());
	strcpy(term_data.cod_tar, mensaje_price->GetCodTar());
	strcpy(term_data.nro_suc, mensaje_price->GetEmpresa());
	strcpy(term_data.nro_caj, mensaje_price->GetTerminal());

	/* Obtiene el tipo de operacion ( 01:T_VENT - 02:T_DEVO - 08:T_PAGO - 09:T_DEVP ) */
	iTipoOperacion = atoi(mensaje_price->GetField(5));

	/* Se buscan los restantes datos de la terminal */
	ret=getDataByNT2(&term_data);
	if ( (ret!=OK) || (term_data.caj_bloq==1) )
	{
		/* Al dar error, loguea los datos de la terminal mal configurada */
		if (term_data.caj_bloq==1)
		{
			LogAlarm.Put (0, "PriceOn: ERROR Caja bloqueada por cierre anterior fallido\n");
		}
		else
		{
			LogAlarm.Put (0, "PriceOn: ERROR (%d) al obtener datos de la terminal\n", ret);
		}

		/* Escribe en el log de errores de terminal */
		LogErrTerminal.Put(0, "Fecha Hora %s", currentTimeLog() );
		LogErrTerminal.Put(0, "Caja: %s - Empresa: %s - Tarjeta: %s - Plan: %s - Evento: PriceOn\n\n", 
								mensaje_price->GetTerminal(),
								mensaje_price->GetEmpresa(),
								mensaje_price->GetCodTar(),
								mensaje_price->ObtPlanSf()); 
		
		/* Arma mensaje de respuesta y lo envia al TPV */
		sprintf(stRta.szRespCA, "102");
		if ( (iTipoOperacion==T_PAGO) || (iTipoOperacion==T_DEVP) )
		{
			Armar_y_Enviar_Respuesta("11", &stRta);
		}
		else
		{
			Armar_y_Enviar_Respuesta("08", &stRta);
		}
		return OK;
	}
	
	/* Se agrega en la cadena del heap el nro_tar original para devolverlo */
	strcpy(heap_data.nro_tar,mensaje_price->GetField(4));
	
	/* Se adapta el mensaje price a la forma de autorizacion */
	mensaje_price->ConvMsgPrice(atoi(term_data.tip_aut));

	/* Completa la estructura de Trace Number */
	TraceNumber.SetNroSuc(term_data.nro_suc);
	TraceNumber.SetNroCaj(term_data.nro_caj);
	TraceNumber.SetNroCA (term_data.nro_ca );
	TraceNumber.SetCodConCie(term_data.cod_con_cie);
	
	/* Si se esta haciendo un cierre de lote genera la respuesta y se la envia de vuelta al price */
	if (CACS.IsCierre(atoi(term_data.nro_ca)))
	{
		if ((CACS.GetSuc(atoi(term_data.nro_ca))==atoi(term_data.nro_suc)) &&
			(CACS.GetCaj(atoi(term_data.nro_ca))==atoi(term_data.nro_caj)))
		{
			/* Arma mensaje de respuesta y lo envia al TPV */
			LogAlarm.Put(0, "PriceOn: ERROR. Cierre de lote activo notificando a Price\n");
			sprintf(stRta.szRespCA, "104");
			if ( (iTipoOperacion==T_PAGO) || (iTipoOperacion==T_DEVP) )
			{
				Armar_y_Enviar_Respuesta("11", &stRta);
			}
			else
			{
				Armar_y_Enviar_Respuesta("07", &stRta);
			}
			return OK;
		}
	}
	
	/* Completar el mensaje con los datos generados por nosotros	*/
	if (!strcmp(term_data.uco_seg,"S"))
	{
		mensaje_price->SetCodSeg();
	}
	else
	{
		mensaje_price->SetNoCodSeg();
	}
	
	/* Setea el centro autorizador */
    mensaje_price->SetNroCAPrice(term_data.nro_ca);

	/* Convierte el mensaje a formato ISO */
	mensaje_iso=new Iso_Msg();
	mensaje_iso->SetNroCA8583(term_data.nro_ca);
	*mensaje_iso=*mensaje_price;

	sprintf(szFHtransm, currentTimestamp());
	mensaje_iso->PutField(7, szFHtransm);	
	strcpy(aux_str, TraceNumber);
	mensaje_iso->PutField(11, aux_str); 	
	mensaje_iso->PutField(24, term_data.cod_red);	
	mensaje_iso->PutField(41, term_data.nro_caj_ca);	
	mensaje_iso->PutField(49, term_data.cod_mon);	
	trx_data.NroLot(term_data.nro_lot);
	trx_data.CodMon(term_data.cod_mon);	
	sprintf(aux_str, "%-15s", term_data.nro_com);
	mensaje_iso->PutField(42, aux_str);

	/* Si hora operacion mayor a transmision se rechaza */
	/* Quitar si sincronizan hora los servidores        */
	switch (DBTipoProtocoloISO(term_data.nro_ca))
	{
	case PROT_ISO_AMEX: 
		memset(szFHoperac, 0, sizeof(szFHoperac));
		strcpy(szFHoperac, mensaje_iso->GetField(13));
		strcat(szFHoperac, mensaje_iso->GetField(12));
		if (strcmp(szFHoperac, szFHtransm)>0)
		{
			LogAlarm.Put(0, "PriceOn: ERROR fecha Suc[%s] Ter[%s] Operac[%s] Transm[%s]\n", 
							mensaje_price->GetSucursal(), mensaje_price->GetTerminal(),
							szFHoperac, szFHtransm);
			sprintf(stRta.szRespCA, "109");
			Armar_y_Enviar_Respuesta("02", &stRta);
			return OK;	
		}
		break;
	default:
		break;
	}

	/* Modificacion PINPAD */
	iHayPinPad = mensaje_price->UsePinPad();
	if (iHayPinPad)
	{
		/* Arma el codigo de procesamiento */
		lCodCuenta = atol(mensaje_price->GetField(31));
		if ( (lCodCuenta != PINPAD_CA_P) && (lCodCuenta != PINPAD_CC_P) &&
		     (lCodCuenta != PINPAD_CA_D) && (lCodCuenta != PINPAD_CC_D) )
		{
			lCodCuenta = PINPAD_CA_P;	/* Caja de ahorro en pesos por defecto */
		}
		lCodProc = atol(mensaje_iso->GetField(3)) + lCodCuenta * 1000;
		sprintf(szCodiProc, "%06d", lCodProc);
		mensaje_iso->PutField(3, szCodiProc);

		LogAlarm.Put(0, "PriceOn: Codigo de procesamiento PPAD: %s\n", szCodiProc);

		/* Agrega el pinpad al mensaje */
		memset(szPinPad, 0, sizeof(szPinPad));
		mensaje_price->GetPinPad(szPinPad);
		mensaje_iso->PutField(52, szPinPad);
	}
	/* Fin manejo PinPad */

	/* Obtiene montos de la operacion */
	lImpoTran = atol(mensaje_price->GetField( 6));
	lCashBack = atol(mensaje_price->GetField(32));
	
	/* CashBack Visa. Campo 4 = Compra + Retiro */
	if (lCashBack>0)
	{
		switch (term_data.prot_cash[0])
		{
		case CASHBACK_VISA: 
			sprintf(aux_str, "%012ld", lImpoTran+lCashBack);
			mensaje_iso->PutField(4, aux_str);
			break;
		case CASHBACK_POSN:
			sprintf(aux_str, "%012ld", lImpoTran);
			break;
		default:
			break;
		}
		LogAlarm.Put(0, "PriceOn: CashBack. Prot:%c Imp:%ld Ret:%ld Tot:%ld\n", 
					 term_data.prot_cash[0], lImpoTran, lCashBack, atol(aux_str));
	}
	
	/* Arma los datos de la transaccion para la BD */
	mensaje_price->GetDBData(trx_data);
	mensaje_iso->GetDBData(trx_data);
	sprintf(aux_str,"%02d",M_CEAU);
	trx_data.ModAut(aux_str);
	trx_data.CanRet("0000");
	trx_data.NroCA(term_data.nro_ca);
	trx_data.NroCajCa(term_data.nro_caj_ca);
	trx_data.NroCom(term_data.nro_com); 
	trx_data.NroCuo(mensaje_price->ObtCuotas());
	trx_data.PlanISO(term_data.plan_iso);
	trx_data.PlanSF(mensaje_price->ObtPlanSf()); 
	trx_data.NroRef("");

	/* Pago de resumen */
	iTipoOperacion = atoi(mensaje_price->GetField(5));
	switch (iTipoOperacion)
	{
	case T_PAGO:
		sprintf(aux_str, "%02d", T_PAGO);
		trx_data.CodTrx(aux_str);
		sprintf(szCodiProc, "%06d", OPCODE_VISA_PAGO_RESUMEN);
		trx_data.CodPro(szCodiProc);
		mensaje_iso->PutField(3, szCodiProc);
		break;
	case T_DEVP:
		sprintf(aux_str, "%02d", T_DEVP);
		trx_data.CodTrx(aux_str);
		sprintf(szCodiProc, "%06d", OPCODE_VISA_DEVO_RESUMEN);
		trx_data.CodPro(szCodiProc);
		mensaje_iso->PutField(3, szCodiProc);
		break;
	}

	/* Codigo de procesamiento */
	if ( (lCashBack>0) && (iTipoOperacion==1) )
	{
		lCodProc = 0;
		switch ( term_data.prot_cash[0] )
		{
		case CASHBACK_VISA: 
			lCodProc = OPCODE_VISA_VEN_CASHBACK;
			break;
		case CASHBACK_POSN:
			lCodProc = (((atol(mensaje_iso->GetField(3))/1000)%10)*1000) + OPCODE_POSN_VEN_CASHBACK;
			break;
		}
		if (lCodProc)
		{
			sprintf(szCodiProc, "%06d", lCodProc);
			mensaje_iso->PutField(3, szCodiProc);
			trx_data.CodPro(szCodiProc);
			LogAlarm.Put(0, "PriceOn: Codigo de procesamiento CASH: %s\n", szCodiProc);
		}
	}
	
	/* Numero de cuenta */
	memset(szNroCta, 0, sizeof(szNroCta));

	/* Agrega peticion de numero de cuenta */
	if (strcmp( mensaje_price->GetField(21) , "01") == 0) 
	{
		sprintf(aux_str, "%s", CAMPO_NRO_CUENTA);
		strcat(szNroCta, aux_str);
	}

	/* Agrega fecha de diferimento (Si no es devolucion) */
	if (term_data.dias_dif > 0)
	{
		char szFechaTrx[32];
		char szFechaDif[32];
		sprintf(szFechaTrx,"%04d%4.4s",ObtYear(),trx_data.FecLoc());
		if( (atoi(trx_data.CodTrx())!=T_DEVO) && (atoi(trx_data.CodTrx())!=T_DEVP) )
		{
			if (getFechaDif(szFechaTrx, term_data.dias_dif, szFechaDif)==0)
			{
				sprintf(aux_str, "%s%s", CAMPO_FECHA_DIFE, szFechaDif);
				strcat(szNroCta, aux_str);
			}
		}
	}

	/* Agrega campo 59 */
	if (strlen(szNroCta)>0)
	{
		sprintf(aux_str, "%03d%s", strlen(szNroCta), szNroCta);
		ret = mensaje_iso->PutField(59, aux_str);
		LogAlarm.Put(10, "PriceOn: Campo 59:[%s] Ret:[%d]\n", aux_str, ret);
	}

	strcpy(heap_data.anul_onl,  "0");
	strcpy(heap_data.plan_iso,  term_data.plan_iso);
	strcpy(heap_data.nro_com,   term_data.nro_com);
	strcpy(heap_data.trans_ori, "0000");
	strcpy(heap_data.fecha_ori, "000000");

	/* Arma el campo cuotas */
	strcpy(aux_str, mensaje_price->ObtCuotas());
	
	/* #37322 Cuotas articulos nacionales */
	if (term_data.plan_esp > 0) 
	{
		sprintf(aux_str, "%03d", term_data.plan_esp);
	}

	sprintf(szCuotas, "003%1.1s%2.2s",trx_data.PlanISO(), &aux_str[1]);
	
	/* Compras AMEX de contado no se envia campo 48 */
	switch (DBTipoProtocoloISO(term_data.nro_ca))
	{
	case PROT_ISO_AMEX: 
		if (strcmp(szCuotas, "003001")==0) 
		{
			memset(szCuotas, 0, sizeof(szCuotas));
		}
		break;
	default:
		break;
	}

	/*** Se verifica que sea una devolucion para convertirla en anulacion ***/
	/*** en caso que la transaccion original se encuentre en la base y    ***/
	/*** sea de la fecha en curso                                         ***/
	
	LogAlarm.Put(8, "PriceOn: Codigo de transaccion:[%s]\n", trx_data.CodTrx());
	if( (atoi(trx_data.CodTrx())==T_DEVO) || (atoi(trx_data.CodTrx())==T_DEVP) )
	{
		/* Obtiene la caja y transaccion  */
		strcpy(CajDevol,trx_data.NroCaj());
		strcpy(TrxDevol,trx_data.NroTrx());
		LogAlarm.Put(0, "PriceOn: Devolucion. CAut:[%s] TerOri:[%s] CajDevol:[%s]\n", term_data.nro_ca, CajDevol, TrxDevol);

		/* Agrega el monto a consulta de anulaciones */
		trx_data.Monto(mensaje_price->GetField(6));
		
		/* Reemplaza caja y transaccion por los de la operacion original */
		trx_data.NroCaj(mensaje_price->GetField(27));
		trx_data.NroTrx(mensaje_price->GetField(28));

		/* Obtiene los datos de la operacion */
		StrDataRev=*(trx_data.GetDataRev());
		
		/* Agrega el plan */
		strcpy(StrDataRev.plan_sf, trx_data.PlanSF());

		/* Actualiza el estado de la transaccion y trae los datos */
		ret=DBTrx.UpdAnulVenta(&StrDataRev);
		
		strcpy(CajVenta,trx_data.NroCaj());
		strcpy(TrxVenta,trx_data.NroTrx());

		LogAlarm.Put(0, "PriceOn: Actualizacion anulacion venta. Ret:[%d], Errno:[%d]\n",ret,DBTrx.GetErrno());
		LogAlarm.Put(0, "PriceOn: TerV:[%s], TrxV[%s] TerD:[%s], TrxD[%s]\n", CajVenta, TrxVenta, CajDevol, TrxDevol);
		
		/* Devolucion de pago de resumen */
		if (atoi(trx_data.CodTrx())==T_DEVP)
		{
			LogAlarm.Put(0, "PriceOn: Devolucion pago de resumen\n");
			if ( (ret==1403) || (ret==-1403) )
			{
				LogAlarm.Put(0, "PriceOn: No existe original\n");
				sprintf(stRta.szRespCA, "108");
				Armar_y_Enviar_Respuesta("02", &stRta);
				return OK;
			}
		}
		
		/* Error en la actualizacion */
		if (ret==NOOK)
		{
			LogAlarm.Put(0, "PriceOn: ERROR (%d) al actualizar BD en devolucion\n", DBTrx.GetErrno());
			if (atoi(trx_data.CodTrx())==T_DEVP)
			{
				sprintf(stRta.szRespCA, "107");
				Armar_y_Enviar_Respuesta("02", &stRta);
				return OK;
			}
		}

		/* La transaccion esta viajando (estado 01) */
		if (ret==NORTA)
		{
			/* Arma mensaje de respuesta y lo envia al TPV */
			LogAlarm.Put(0, "PriceOn: ERROR al esperar respuesta en devolucion\n");	
			sprintf(stRta.szRespCA, "101");
			Armar_y_Enviar_Respuesta("02", &stRta);
			return OK;
		} 
		
		/* La transaccion original esta pendiente de envio */
		if (ret==INSANULOFF)
		{
			LogAlarm.Put(0, "PriceOn: ANULACION de transaccion original no enviada\n");

			if ( atol(StrDataRev.retiro) > 0 )
			{
				LogAlarm.Put(0, "PriceOn: Anulacion offline con cashback no permitida");	
				sprintf(stRta.szRespCA, "110");
				Armar_y_Enviar_Respuesta("02", &stRta);
				return OK;
			}

			/* Se arma la transaccion */
			sprintf(aux_str, "%02d", T_OFLI);
			trx_data.ModEnv(aux_str);
			sprintf(aux_str, "%02d", M_CRED);
			trx_data.ModAut(aux_str);
			trx_data.NroTrc("-1");
			sprintf(aux_str, "%02d", E_NOAN);
			trx_data.CodEst(aux_str);
			trx_data.CodAut(getCodAutLocal(trx_data.CodTar()));
			sprintf(aux_str, "%04d%4.4s", ObtYear(), trx_data.FecLoc());
			trx_data.FecTrx(aux_str);
			trx_data.NroCaj(CajDevol);
			trx_data.NroTrx(TrxDevol);
			
			/* Fecha del dia */
			memset(FecVenta, 0, sizeof(FecVenta));
			memcpy(&FecVenta[0], &aux_str[6], 2);
			memcpy(&FecVenta[2], &aux_str[4], 2);
			memcpy(&FecVenta[4], &aux_str[2], 2);

			/* Se inserta como venta anulada para no enviar al CA */
			LogAlarm.Put(0, "PriceOn: Inserta venta anulada (NOEN)\n");
			ret= DBTrx.Insert(trx_data.GetInsVenData(), szRowId);
			LogAlarm.Put(0, "PriceOn: Resultado insercion: %d\n", ret);
			
			/* Arma mensaje de respuesta y lo envia al TPV */
			sprintf(stRta.szCodAut, trx_data.CodAut());
			sprintf(stRta.szTermin, term_data.nro_caj_ca);
			sprintf(stRta.szComerc, term_data.nro_com);
			sprintf(stRta.szPlnIso, term_data.plan_iso);
			sprintf(stRta.szNroLot, term_data.nro_lot);
			sprintf(stRta.szFecOri, FecVenta);
			sprintf(stRta.szTicOri, TrxVenta);
			sprintf(stRta.szPlanSF, term_data.plan_sf);
			sprintf(stRta.szRespCA, "000");
			switch (DBTipoProtocoloISO(term_data.nro_ca))
			{
			case PROT_ISO_AMEX: 
				sprintf(stRta.szProtoc, "A");
				break;
			default:
				sprintf(stRta.szProtoc, "B");
				break;
			}
			Armar_y_Enviar_Respuesta("00", &stRta);
			return OK;
			
		} /* end del if INSANULOFF */
		
		/**********************/
		/* ANULACIONES ONLINE */
		/**********************/

		if (ret==INSANUL)
		{
			LogAlarm.Put(0, "PriceOn: Se continua como ANULACION\n");

			/* Continua anulacion si monto cashback es coincidente */
			if ( atol(StrDataRev.retiro) != atol(trx_data.Retiro()) )
			{
				LogAlarm.Put(0, "PriceOn: Difiere monto cashback. VENTA:[%ld] ANULA:[%ld]\n", 
									atol(StrDataRev.retiro), atol(trx_data.Retiro()));
				sprintf(stRta.szRespCA, "110");
				Armar_y_Enviar_Respuesta("02", &stRta);
				return OK;	
			}

			/* INSERTA DEVOLUCION */
			
			/* Modo de envio "00" */
			sprintf(aux_str, "%02d", T_ONLI);
			trx_data.ModEnv(aux_str);
			
			/* Modo de autorizacion "10" */
			sprintf(aux_str, "%02d", M_CRED);
			trx_data.ModAut(aux_str);

			/* Numero de trace */
			trx_data.NroTrc("-1");

			/* Codigo de autorizacion */
			trx_data.CodAut("-1");

			/* Codigo de estado E_ANVE=28 */
			sprintf(aux_str, "%02d", E_ANVE);
			trx_data.CodEst(aux_str);

			/* Fecha de transaccion */
			sprintf(aux_str, "%04d%4.4s", ObtYear(), trx_data.FecLoc());
			trx_data.FecTrx(aux_str);
			
			/* Terminal */
			trx_data.NroCaj(CajDevol);
			
			/* Transaccion */
			trx_data.NroTrx(TrxDevol);
			
			/* Terminal original de venta */
			trx_data.NroCajOri(CajVenta);

			/* Transaccion original de venta */
			trx_data.NroTicOri(TrxVenta);

			/* Numero de lote (Caja venta para cerrar) */
			trx_data.NroLot(term_data.nro_lot);

			/* Codigo de seguridad */
			trx_data.CodSeg(" ");

			/* Track 1 */
			/*trx_data.Track1(" ");*/

			/* Track 2 */
			/*trx_data.Track2(" ");*/

			/* Borra intento de anulacion anterior */
			DBTrx.DeleteRech(trx_data.GetInsVenData(), E_RECH); /* Estado = '03' */
 			LogAlarm.Put(0, "PriceOn: DeleteRech '%02d' : %d\n", E_RECH, DBTrx.GetErrno());

			/* Se inserta devolucion para conciliar */
			if (DBTrx.Insert(trx_data.GetInsVenData(), szRowId))
			{
				LogAlarm.Put(0, "PriceOn: ERROR al insertar devolucion: %d\n", DBTrx.GetErrno());
				sprintf(stRta.szRespCA, "105");
				if ( (iTipoOperacion==T_PAGO) || (iTipoOperacion==T_DEVP) )
				{
					Armar_y_Enviar_Respuesta("11", &stRta);
				}
				else
				{
					Armar_y_Enviar_Respuesta("02", &stRta);
				}
				return OK;
			}
			strcpy(heap_data.rowid, szRowId);
			LogAlarm.Put(0, "PriceOn: Insert devolucion rowid [%s]: %d\n", szRowId, ret);

			/* TRANSFORMA DEVOLUCION EN ANULACION */

			/* Obtiene datos de la caja de venta */
			strcpy(term_data.nro_caj, CajVenta);
			ret=getDataByNT2(&term_data);

			/* Codigo de procesamiento */
			if ( (lCashBack>0) && (iTipoOperacion==2) )
			{
				lCodProc = 0;
				switch ( term_data.prot_cash[0] )
				{
				case CASHBACK_VISA: 
					lCodProc = OPCODE_VISA_ANU_CASHBACK;
					break;
				case CASHBACK_POSN:
					lCodProc = (((atol(mensaje_iso->GetField(3))/1000)%10)*1000) + OPCODE_POSN_ANU_CASHBACK;
					break;
				}
				if (lCodProc)
				{
					sprintf(szCodiProc, "%06d", lCodProc);
					mensaje_iso->PutField(3, szCodiProc);
					trx_data.CodPro(szCodiProc);
				}
			}
			else
			{
				lCodProc = 20000 + atol(mensaje_iso->GetField(3)) % 10000;
				sprintf(szCodiProc, "%06d", lCodProc);
				trx_data.CodPro(szCodiProc);
			}
			LogAlarm.Put(0, "PriceOn: Codigo de procesamiento ANUL: %s\n", szCodiProc);

			/* Cambia codigo de transaccion a 05 (Anulacion venta online) */
			sprintf(aux_str, "%02d", T_ANVE);
			trx_data.CodTrx(aux_str);
		
			/* Modo de envio */
			sprintf(aux_str, "%02d", T_ANUL);
			trx_data.ModEnv(aux_str);

			/* Modo de autorizacion */
			sprintf(aux_str, "%02d", M_CEAU);
			trx_data.ModAut(aux_str);

			/* Numero de terminal */
			trx_data.NroCaj(CajVenta);
		
			/* Numero de transaccion */
			trx_data.NroTrx(TrxVenta);
			
			/* Numero de lote */
			trx_data.NroLot(term_data.nro_lot);
			
			/* Numero de caja CA */
			trx_data.NroCajCa(term_data.nro_caj_ca);
			
			/* Numero de comercio */
			trx_data.NroCom(term_data.nro_com); 

			/* Fecha de la transaccion */
			trx_data.FecLoc(StrDataRev.fec_loc);

			/* Numero de trace */
			TraceNumber.SetNroSuc(term_data.nro_suc);
			TraceNumber.SetNroCaj(term_data.nro_caj);
			TraceNumber.SetNroCA (term_data.nro_ca );
			TraceNumber.SetCodConCie(term_data.cod_con_cie);
			strcpy(aux_str, TraceNumber);
			trx_data.NroTrc(aux_str);

			/* CONVIERTE MENSAJE ISO A ANULACION */
			
			/* Campo 3: Codigo de procesamiento */
			mensaje_iso->PutField(3, trx_data.CodPro());

			/* Campo 11: Numero de Trace */
			mensaje_iso->PutField(11, trx_data.NroTrc()); 	

        		/* Campo 12: Hora local (trx original) */
    			sprintf(aux_str, trx_data.FecLoc());
			//// mensaje_iso->PutField(12, &aux_str[4]);

			/* Campo 13: Fecha local (trx original) */
			sprintf(aux_str, "%4.4s", trx_data.FecLoc());
			//// mensaje_iso->PutField(13, aux_str);

			/* Campo 37: Numero referencia anulacion. Se agrega */
			mensaje_iso->PutField(37, StrDataRev.nro_ref);
			trx_data.NroRef(StrDataRev.nro_ref);

			/* Campo 38: Codigo de autorizacion */
			switch (DBTipoProtocoloISO(trx_data.NroCA()))
			{
			case PROT_ISO_AMEX:
				if (strlen(StrDataRev.cod_aut)>0)
				{
					mensaje_iso->PutField(38, StrDataRev.cod_aut);
					trx_data.CodAut(StrDataRev.cod_aut);
				}
				break;
			default:
				break;
			}

			/* Campo 41: Numero de caja CA */
			mensaje_iso->PutField(41, term_data.nro_caj_ca);	
			
			/* Campo 42: Numero de comercio CA */
			sprintf(aux_str, "%-15s", term_data.nro_com);
			mensaje_iso->PutField(42, aux_str);

			/* Campo 62: Numero de ticket */
			sprintf(aux_str, "004%04d", atoi(TrxVenta));
			mensaje_iso->PutField(62, aux_str);

			/* Almacena transaccion de venta */
			sprintf(NroTrxAux, "%s", TrxVenta);	
			
			/* Marca anulacion online SI */
			strcpy(heap_data.anul_onl, "1");		
		}
		else
		{
			LogAlarm.Put(0, "PriceOn: Se continua como DEVOLUCION\n");

			/* Continua devolucion solo si monto cashback es cero */
			if (lCashBack>0)
			{
				LogAlarm.Put(0, "PriceOn: Monto cashback no es cero [%ld]\n", lCashBack);
				sprintf(stRta.szRespCA, "110");
				Armar_y_Enviar_Respuesta("02", &stRta);
				return OK;	
			}
			
			/* Marca anulacion online NO */
			strcpy(heap_data.anul_onl, "0");

			/* Restaura caja y terminal del mensaje */
			trx_data.NroCaj(CajDevol);
			sprintf(NroTrxAux, "%s", trx_data.NroTrx());	
			trx_data.NroTrx(TrxDevol);
		}
		
		/* Arma el campo 48 de plan, transaccion y fecha originales */
		if(useCampCuot(trx_data.NroCA())==1)
		{
			trx_data.NroCajOri(CajVenta);
			trx_data.NroTicOri(NroTrxAux);
			DBTrx.SelTrxOrig(&StrDataRev);
			trx_data.FecOri(StrDataRev.fec_ori);
			
			LogAlarm.Put(0, "PriceOn: Datos orig. Fecha:[%s] Trx:[%s]\n", trx_data.FecOri(), trx_data.NroTicOri());
			if (heap_data.anul_onl[0]=='0') /* Si es devolucion (no es anulacion) */
			{
				strcpy(aux_str, mensaje_price->ObtCuotas());
				
				/* #37322 Cuotas articulos nacionales */
				if (term_data.plan_esp > 0)
				{
					sprintf(aux_str, "%03d", term_data.plan_esp);
				}
				
				sprintf(szCuotas, "013%1.1s%2.2s%04d%6.6s", 
						   trx_data.PlanISO(), &aux_str[1], atoi(trx_data.NroTicOri()), trx_data.FecOri()); 
			}
		}
		
		/* Almacena datos para recuperar con la respuesta */
		strcpy(heap_data.trans_ori, trx_data.NroTicOri());
		strcpy(heap_data.fecha_ori, trx_data.FecOri());

	} /* Fin manejo devoluciones */

	// Campo 48: Cuotas
	if ( strlen(szCuotas) > 0 )
	{
		mensaje_iso->PutField(48, szCuotas);
		LogAlarm.Put(1, "PriceOn: Campo 48 [%s]\n", mensaje_iso->GetField(48));
	}

        /* EMV */
        if(strlen(mensaje_price->GetField(34)) || strlen(mensaje_price->GetField(36)))
        {
            LogAlarm.Put(1, "PriceOn: Mensaje * EMV *\n");
            if(strlen(mensaje_price->GetField(34)))
            {
                sprintf(szCriptograma, "%03d%s", strlen(mensaje_price->GetField(34)), mensaje_price->GetField(34));
                mensaje_iso->PutField(55, szCriptograma);
            }
            sprintf(szVersionEMV, "%03d%s", strlen(mensaje_price->GetField(35)), mensaje_price->GetField(35));
            mensaje_iso->PutField(60, szVersionEMV);
            mensaje_iso->PutField(19, "032");

            strcat(szEMVProductList, "016  02100010040705");
            /*szEMVProductList[3] = 0x0;
            szEMVProductList[4] = 0x14;*/
            szEMVProductList[3] = 1;
            szEMVProductList[4] = 4;

            /*if(strlen(mensaje_price->GetField(36)))
            {
                strcat(szEMVProductList, "");
            } */
            mensaje_iso->PutField(59, szEMVProductList);
            ///mensaje_iso->PutField(22, "052");

            ///mensaje_iso->PutField(23, mensaje_price->GetField(37));
            
            //mensaje_iso->ClearField(12);
            //mensaje_iso->ClearField(13);

            ///mensaje_iso->PutField(46, "0011");
            /*if(!strlen(mensaje_price->GetField(30)))
            {
                mensaje_iso->PutField(46, "0011");
            }*/
        }

	/* Verifica si hay transacciones en vuelo */
	pos_ocup = P.IsPosFree(term_data.nro_ca, term_data.nro_suc, term_data.nro_caj);
	if (pos_ocup)
	{
		TrxEnVuelo=0;
	}
	else
	{
		TrxEnVuelo=1;
	}

	/* Verificamos el estado del canal X.25 */


	/*  Modificacion: 3/2/98
	Autor: Rolando Loustric
	Objetivo: Se utiliza un flag interno para el estado del canal. Este flag
	es utilizado antes del Insert y para resolver la peticion.
	Antes se consultaba CACS.IsDown, y en caso de cambiar el 
	estado del canal en medio del evento se producia un error de 
	consistencia        */
	channel_down = CACS.IsDown(atoi(term_data.nro_ca));

	/* Si el canal esta caido o hay transacciones en vuelo */
	if (channel_down||TrxEnVuelo)
	{
		LogAlarm.Put(0, "PriceOn: Centro abajo [%d] Trx en vuelo [%d]. Autoriza localmente. CAut [%s]\n", 
									channel_down, TrxEnVuelo, term_data.nro_ca);
		if (iTipoOperacion != T_PAGO)		
		{
			/* Intenta aprobar localmente */
			
			str_get_total	opers_data;
			str_get_limit	limit_data;
			
			/* Obtiene el numero de tarjeta */
			strcpy(aux_str, mensaje_price->GetField(4));
			for (cont=0; cont<strlen(aux_str); cont++)
			{
				if (aux_str[cont]==' ')
				{
					aux_str[cont]='\0';
				}
			}
		
			/* Carga datos para consultar los totales de la tarjeta */
			sprintf(opers_data.nro_tar, "%-*s", sizeof(opers_data.nro_tar)-1, aux_str);
			sprintf(opers_data.cod_est, "%0*d", sizeof(opers_data.cod_est)-1, E_PEND);
			strcpy(opers_data.cod_tar, term_data.cod_tar);
			strcpy(opers_data.plan_sf, term_data.plan_sf);
			strcpy(opers_data.cod_trx, trx_data.CodTrx());
		
			/* Carga datos para obtener los limites de respaldo del tipo de tarjeta y plan */
			strncpy(limit_data.cod_tar, mensaje_price->GetCodTar(), sizeof(limit_data.cod_tar));
			strncpy(limit_data.plan_sf,	mensaje_price->ObtPlanSf(),	sizeof(limit_data.plan_sf));
	
			/* Obtiene los limites de respaldo del tipo de tarjeta */
			ret=getLimit(&limit_data);
			if (ret!=OK)
			{
				LogAlarm.Put(0, "PriceOn: ERROR (%d) al obtener el limite de tarjeta\n", ret);
				return NOOK;
			}
			
			LogAlarm.Put(0, "PriceOn: Limites. General:%.2f - Cuotas:%.2f - Plan %s:%.2f\n", 
						(double)limit_data.limite/100.0 , (double)limit_data.limcuot/100.0 ,
						limit_data.plan_sf, (double)limit_data.limplan/100.0 );
		
			/* Obtiene el total comprado con la tarjeta */
			ret=getTotalGeneral(&opers_data);
			if (ret!=OK)
			{
				LogAlarm.Put(0, "PriceOn: ERROR (%d) al obtener total de tarjeta!!\n",	ret);
				return NOOK;
			}
			LogAlarm.Put(0, "PriceOn: Total de la tarjeta: %.2f\n", (double)opers_data.monto/100);
		
			/* Cambia el modo de la operacion a OFF-LINE */
			sprintf(aux_str, "%02d", T_OFLI); 
			trx_data.ModEnv(aux_str);

			/* Cambia el modo de ingreso */
			switch (DBTipoProtocoloISO(trx_data.NroCA()))
			{
			case PROT_ISO_AMEX:
				if (strcmp(trx_data.ModIng(), "072")==0)
				{
					trx_data.ModIng("012");
				}
				if (strcmp(trx_data.ModIng(), "062")==0)
				{
					trx_data.ModIng("022");
				}
				break;
			default:
				break;
			}

			/* Pone el modo de autorizacion por Credito */
			sprintf(aux_str, "%02d", M_CRED);
			trx_data.ModAut(aux_str);
				
			/* Pone el numero de trace (NULL) */
			trx_data.NroTrc("-1");
			
			if (heap_data.anul_onl[0]=='1')
			{
				LogAlarm.Put(0, "PriceOn: Anulacion offline no permitida\n");
				sprintf(aux_str, "%02d", E_RECH);
				trx_data.CodEst(aux_str);
				limite=NOOK;
			}
			else
			{
				/* Obtiene el monto de la transaccion en curso */
				long monto;
				monto=atol(mensaje_price->GetField(6));
				LogAlarm.Put(0, "PriceOn: Esta operacion: %.2f\n", (double)monto/100);
				LogAlarm.Put(0, "PriceOn: Total general de la tarjeta: %.2f\n", (double)opers_data.monto/100.0);
			
				/* Si las compras realizadas anteriormente mas la actual supera el limite */
				if ((opers_data.monto+monto)>limit_data.limite)
				{
					/* Se prepara el estado para registrar la operacion como rechazada */
					LogAlarm.Put(0, "PriceOn: Supera el limite\n");
					limite=NOOK;
					sprintf(aux_str, "%02d", E_RECH);
					trx_data.CodEst(aux_str);
				}
				else
				{
					/* Si el plan es en cuotas */
					if (strncmp(term_data.plan_sf, "00", 2) != 0)
					{
						/* Obtiene el total comprado en cuotas */
						ret= getTotalCuotas(&opers_data);
						if (ret!=OK)
						{
							LogAlarm.Put(0, "PriceOn: ERROR (%d) al obtener el total de la tarjeta en cuotas\n",ret);
							return NOOK;
						}
						LogAlarm.Put(0, "PriceOn: Total de la tarjeta en cuotas: %.2f\n", (double)opers_data.monto/100.0);
						
						/* Si las compras realizadas anteriormente en cuotas mas la actual supera el limite */		
						if ((opers_data.monto+monto)>limit_data.limcuot)
						{
							limite=NOOK;
						}
						else
						{
							/* Obtiene el total comprado en cuotas para ese plan */
							ret= getTotalPlan(&opers_data);
							if (ret!=OK)
							{
								LogAlarm.Put(0, "PriceOn: ERROR (%d) al obtener el total de tarjeta para el plan\n",ret);
								return NOOK;
							}
							LogAlarm.Put(0, "PriceOn: Total de la tarjeta para el plan: %.2f\n", (double)opers_data.monto/100.0);

							/* Si las compras realizadas anteriormente para el plan mas la actual supera el limite */			
							if ((opers_data.monto+monto)>limit_data.limplan)
							{
								limite=NOOK;
							}
							else
							{
								limite=OK;
							}           
						}
					}
					else
					{
						limite=OK;
					}
				
					/* Si la tarjeta tiene limite de respaldo para operrar offline */
					if (limite==OK)
					{	
						LogAlarm.Put(0, "PriceOn: No supera el limite\n");
						sprintf(aux_str, "%02d", E_PEND);
						trx_data.CodEst(aux_str);
						/*Modificacion: Codigo de autorizacion local*/
						/*configurable [28-12-2000][DL]*/
						sprintf(aux_str, "%s", getCodAutLocal(trx_data.CodTar()));
						trx_data.CodAut(aux_str);
					}
					else
					{
						LogAlarm.Put(0, "PriceOn: Supera el limite\n");
						sprintf(aux_str, "%02d", E_RECH);
						trx_data.CodEst(aux_str);
					}
				}
			}
		}		
		else /* iTipoOperacion == T_PAGO */
		{
			/* No se permite pago de resumen offline en cuotas */
			if (strncmp(term_data.plan_sf, "00", 2) != 0)
			{
				LogAlarm.Put(0, "PriceOn: Pago de resumen offline en cuotas no permitido\n");
				sprintf(aux_str, "%02d", E_RECH);
				trx_data.CodEst(aux_str);
				limite=NOOK;
			}
			else
			{
				/* Cambia el modo de la operacion a OFF-LINE */
				sprintf(aux_str, "%02d", T_OFLI); 
				trx_data.ModEnv(aux_str);

				/* Cambia el modo de ingreso */
				switch (DBTipoProtocoloISO(trx_data.NroCA()))
				{
				case PROT_ISO_AMEX:
					if (strcmp(trx_data.ModIng(), "072")==0)
					{
						trx_data.ModIng("012");
					}
					if (strcmp(trx_data.ModIng(), "062")==0)
					{
						trx_data.ModIng("022");
					}
					break;
				default:
					break;
				}

				/* Pone el modo de autorizacion por Credito */
				sprintf(aux_str, "%02d", M_CRED);
				trx_data.ModAut(aux_str);
					
				/* Pone el numero de trace (NULL) */
				trx_data.NroTrc("-1");

				/* Pone el codigo de autorizacion */
				sprintf(aux_str, "%s", getCodAutLocal(trx_data.CodTar()));
				trx_data.CodAut(aux_str);
				
				/* Pone el codigo de estado */
				sprintf(aux_str, "%02d", E_PEND);
				trx_data.CodEst(aux_str);		

				/* Acepta siempre el pago offline */
				limite = OK;
			}
		}
	} 
	else
	{
		/* Si no esta caido el canal X.25 se cambia al estado de enviado */
		sprintf(aux_str, "%02d", E_ENVI);
		trx_data.CodEst(aux_str);
		if (heap_data.anul_onl[0]!='1') /* Si no es anulacion */
		{
			trx_data.CodAut("");
		}
		TraceNumber.Inc();
	}

	/* Carga la fecha de la trx */
	sprintf(aux_str,"%04s%4.4s", trx_data.AnoTrx(), trx_data.FecLoc());
	trx_data.FecTrx(aux_str);

	/* Las transacciones rechazadas localmente no se graban en la BD */
	if (atoi(trx_data.CodEst())!=E_RECH)
	{
		LogAlarm.Put(0, "PriceOn: Inserta anulacion. nro_ref[%s] cod_aut[%s]\n", trx_data.NroRef(), trx_data.CodAut());
		ret=DBTrx.Insert(trx_data.GetInsVenData(), szRowId);
	}
	else
	{
		/* Inserta anulacion rechazada para control */
		if (heap_data.anul_onl[0]=='1')
		{
			ret=DBTrx.Insert(trx_data.GetInsVenData(), szRowId);
			LogAlarm.Put(0, "PriceOn: Inserta anulacion rechazada [%d]\n", DBTrx.GetErrno());
		}
		ret=OK;
	}

	/* Cuando se produce un error en el insert verifica existencia de */
	/* rechazadas, en caso de esto ser cierto las borra para permitir */
	/* el nuevo pedido de autorizacion.                               */
	if (ret==NOOK)
	{
		int testRech=0;   /* Testing de variables rechazadas */
		
		testRech=DBTrx.DeleteRech(trx_data.GetInsVenData(), E_RECH); /* Estado = '03' */
		if (testRech==OK)
		{
			LogAlarm.Put(0, "PriceOn: Intento de Reautorizar Trx: [%s] ya rechazada\n", mensaje_price->GetField(11));
			ret=DBTrx.Insert(trx_data.GetInsVenData(), szRowId);
		}
		if ((testRech==OK && ret==NOOK) || testRech==NOOK)
		{
			LogAlarm.Put(0, "PriceOn: ERROR (%d) en %s!!\n", 
								DBTrx.GetErrno(),	testRech==OK ? "REINSERT" : "Insert Original");
			sprintf(stRta.szRespCA, "105");
			if ( (iTipoOperacion==T_PAGO) || (iTipoOperacion==T_DEVP) )
			{
				Armar_y_Enviar_Respuesta("11", &stRta);
			}
			else
			{
				Armar_y_Enviar_Respuesta("02", &stRta);
			}
			return NOOK;
		}
	}

	/* Verificamos el estado del canal X.25                  */
	/* Si esta caido, generamos la respuesta y la devolvemos */
	if (channel_down||TrxEnVuelo)
	{ 
		/* Arma mensaje de respuesta y lo envia al TPV */
		if (limite==OK)
		{
			sprintf(stRta.szCodAut, getCodAutLocal(trx_data.CodTar()));
			sprintf(stRta.szTermin, term_data.nro_caj_ca);
			sprintf(stRta.szComerc, term_data.nro_com);
			sprintf(stRta.szPlnIso, term_data.plan_iso);
			sprintf(stRta.szNroLot, term_data.nro_lot);
			sprintf(stRta.szFecOri, trx_data.FecOri());
			sprintf(stRta.szTicOri, trx_data.NroTicOri());
			sprintf(stRta.szPlanSF, term_data.plan_sf);
			sprintf(stRta.szRespCA, "000");
			switch (DBTipoProtocoloISO(term_data.nro_ca))
			{
			case PROT_ISO_AMEX:	
				sprintf(stRta.szProtoc, "A");
				break;
			default:
				sprintf(stRta.szProtoc, "B"); 
				break;
			}
			Armar_y_Enviar_Respuesta("00", &stRta);
		}
		else
		{
			sprintf(stRta.szRespCA, "103");
			if ( (atoi(trx_data.CodTrx())==T_PAGO) || (atoi(trx_data.CodTrx())==T_DEVP) )
			{
				Armar_y_Enviar_Respuesta("11", &stRta);
			}
			else
			{
				Armar_y_Enviar_Respuesta("38", &stRta);
			}
		}
		return OK;
	}
	else /* El vinculo esta activo */
	{	
		/* Arma los datos para el heap */
		mensaje_price->GetHeapData(&heap_data);
		if (heap_data.anul_onl[0]=='1')
		{
			strcpy(heap_data.nro_term,  CajVenta);
			strcpy(heap_data.nro_trans, TrxVenta);
		}
		
		strcpy(heap_data.plan_sf,   term_data.plan_sf);
		strcpy(heap_data.nro_caj_ca,term_data.nro_caj_ca);
		heap_data.orig_pid=orig_pid;
		
		char idHeap[20];
		/* Arma clave para el heap */
		sprintf(idHeap,"%2.2s%3.3s%5.5s%8.8s", 
							term_data.nro_ca, term_data.nro_suc, term_data.nro_caj, mensaje_iso->GetField(11));
		
		/* Pone los datos en el heap */
		LogAlarm.Put(95, "PriceOn: idHeap [%s] \n", idHeap);		
		LogAlarm.Put(95, "PriceOn: anul_onl[%s] plan_iso[%s] plan_sf[%s] nro_com[%s]\n", 
							heap_data.anul_onl, heap_data.plan_iso, heap_data.plan_sf, heap_data.nro_com);		
		//LogAlarm.Put(0,  "PriceOn: heap_data.rowid [%s] \n", heap_data.rowid);		
		ret=Heap.PutData(idHeap,(char *)&heap_data, sizeof(heap_data));	
		if (ret==NOOK)
		{
			LogAlarm.Put(0, "PriceOn: ERROR (%d) al poner info en Heap\n", Heap.GetErrno());		
			return NOOK;
		}
		
		/* Registrar en la TimeoutQueue		*/
		Cfg.GetItem("TimeOutDaemon", "MsgTimeOut1", aux_str);	
		ret=timeout_queue.SetTimeOut(idHeap,atoi(aux_str), GetType(), "");
		if (ret==NOOK)
		{
			LogAlarm.Put(0, "PriceOn: ERROR (%d) al agregar a TimeOutQueue!!\n", timeout_queue.GetErrno());			
			return NOOK;
		}
		
		/* Aplana el mensaje */
		memset(msg_str,'\0',sizeof(msg_str));
		len=mensaje_iso->GetMsgString(msg_str);

		/* Envia el mensaje al CA */
		LogAlarm.Put(0, "PriceOn: Envia a X.25. CAut [%s]\n", term_data.nro_ca);
		ret=XQueue.SendMsg(atoi(term_data.nro_ca)+1, msg_str, len);
		if (ret==OK)
		{
			/* Bloquea la caja */
			ret = P.SetPosBusy(term_data.nro_ca, term_data.nro_suc, term_data.nro_caj);
			if (ret!=OK)
			{
				LogAlarm.Put(0, "PriceOn: No se pudo bloquear la caja!!\n");
			}
			LogAlarm.Put(2, "PriceOn: Respuesta enviada OK\n");
		}
		else 
		{
			LogAlarm.Put(0, "PriceOn: ERROR al enviar a X25\n");
			return NOOK;
		} 
	}
	return OK;
}
Beispiel #14
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | Cierre::ProcessIt                                          |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Proceso del objeto                                         |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int Cierre::ProcessIt()
{
    char			aux_str[100];
    char			msg_str[2000];
    int				msg_len;
    int				ret;
    str_heap_data	heap_data;
    BatchData		batch_data;
    str_sel_ntdata	term_data;
	char			aux_str1[100];
    char			idHeap[20];

	/* Obtiene los datos del mensaje */
    strcpy(term_data.nro_caj_ca, mensaje_iso->GetField(41));
    strcpy(term_data.nro_com   , mensaje_iso->GetField(42));
    
	/* Completa la estructura con los datos del mensaje */
	batch_data.NroCajCa(term_data.nro_caj_ca);

	/* Obtiene datos de la terminal */
	ret=getDataByCACie(&term_data);
	if (ret!=OK)
	{
		LogAlarm.Put( 0, "Cierre: ERROR (%d) al obtener datos de la terminal\n", ret);
		return NOOK;
	}

	/* Indica al objeto TraceNmbr el centro autorizador */
    TraceNumber.SetNroSuc(term_data.nro_suc);
    TraceNumber.SetNroCaj(term_data.nro_caj);
    TraceNumber.SetNroCA (term_data.nro_ca );
    TraceNumber.SetCodConCie(term_data.cod_con_cie);

    /* Completar el mensaje con los datos generados */
    mensaje_iso->PutField(7, currentTimestamp());
    strcpy(aux_str, TraceNumber);
    TraceNumber.Inc();
    mensaje_iso->PutField(11, aux_str); 
    mensaje_iso->PutField(15, currentTimestamp());

    /* Chequea consistencia del mensaje	*/
	LogAlarm.Put(95, "Cierre: Chequea consistencia del mensaje\n");
	if (!mensaje_iso->ChkReady())
	{
		LogAlarm.Put( 0, "Cierre: ERROR de consistencia en el mensaje\n");
		return NOOK;
	}

    /* Registrar transaccion en TrxHeap	*/
    LogAlarm.Put(95, "Cierre: Obtiene datos para el Heap\n");
    heap_data.orig_pid=orig_pid;

	/* Pone datos en el heap */
    LogAlarm.Put(95, "Cierre: Poniendo datos en el Heap.\n");
    sprintf(idHeap,"%2.2s%3.3s%5.5s%8.8s",term_data.nro_ca,term_data.nro_suc,term_data.nro_caj,mensaje_iso->GetField(11));
    ret=Heap.PutData(idHeap,(char *)&heap_data, sizeof(heap_data));
	if (ret==NOOK)
	{
		LogAlarm.Put(0, "Cierre: ERROR (%d) al poner los datos en el heap!!\n", Heap.GetErrno());
		return NOOK;
	}

    /* Registra en la TimeoutQueue con un timeout diferente a los otros eventos */
    LogAlarm.Put( 5, "Cierre: Agrega a la cola de timeout\n");
    Cfg.GetItem("TimeOutDaemon", "MsgTimeOut500", aux_str1);
    ret=timeout_queue.SetTimeOut(idHeap, atoi(aux_str1), GetType(), ""/*CodSer*/);
	if (ret==NOOK)
	{
		LogAlarm.Put( 0, "Cierre: ERROR (%d) al agregar en cola de timeout!!\n", timeout_queue.GetErrno());
		return NOOK;
	}

    /* Si se graba registro de cierre */
	memset(aux_str1, 0, sizeof(aux_str1));
	Cfg.GetItem("AdminDaemon", "InsertCierre", aux_str1);
	if (aux_str1[0] != 'N')
	{
		/* Completa la estructura */
		batch_data.NroCA(term_data.nro_ca);
		mensaje_iso->GetDBData(batch_data);
		batch_data.CanRet("0000");
		sprintf(aux_str, "%02d", E_ENVI);
		batch_data.CodEst(aux_str);
		batch_data.NroSuc(term_data.nro_suc);
		batch_data.NroCaj(term_data.nro_caj);
		batch_data.NroCom(term_data.nro_com);

		/* Registra en la base de datos */
		LogAlarm.Put( 5, "Cierre: Registra en base de datos\n");
		ret=DBBatch.Insert(batch_data.GetInsData());
		if (ret!=OK)
		{
			LogAlarm.Put( 1, "Cierre: ERROR (%d) al registrar en base de datos\n", DBBatch.GetErrno());
			return NOOK;
		}
	}

	/* Aplana el mensaje */
    msg_len=mensaje_iso->GetMsgString(msg_str);

    /* Envia el mensaje al centro autorizador */
	LogAlarm.Put(0, "Cierre: Envia a X.25. CAut [%s]\n", term_data.nro_ca);
    ret=XQueue.SendMsg(atol(term_data.nro_ca)+1, msg_str, msg_len);
	if (ret!=OK)
	{
		LogAlarm.Put(0, "Cierre: ERROR (%d) mandando mensaje a X.25!!\n", SQueue.GetErrno());
		return NOOK;
	}
    return OK;
}
Beispiel #15
0
/*
+-----------------+------------------------------------------------------------+
| FUNCION         | SndTrxOffLine::ProcessIt                                   |
+-----------------+------------------------------------------------------------+
| DESCRIPCION     | Proceso del objeto                                         |
|                 |                                                            | 
+-----------------+------------------------------------------------------------+
*/
int SndTrxOffLine::ProcessIt()
{
    int             len;
    int             ret;
    int				iCont;
	str_sel_cadata  term_data;
    char            msg_str[2000];
    char            aux_str[20];
    trxOffHeap      infoHeap;         
    DBInfoEnvio     InfoEnvio;        
    str_fet_bu_trx  trxOff;
    int             pos_ocup;
    str_tarjeta     data_tar;
	char			aux_str1[100];	
    DBTrxPk         trxPk;             
    char			idHeap[20];
	char			szFechaEnvio[16];
	int				iErrorBD;
	int				iNroCuotas;

	/* Carga estructura para busqueda de transaccion offline */
    strncpy(trxOff.cod_tar   , CodTarjeta, sizeof(trxOff.cod_tar));
    strncpy(trxOff.cod_est   , "00"      , sizeof(trxOff.cod_est));
    strncpy(trxOff.nro_caj_ca, NroCajCa  , sizeof(trxOff.nro_caj_ca));
    strncpy(trxOff.nro_trx   , NroTrx    , sizeof(trxOff.nro_trx));
	trxOff.nro_caj_ca[sizeof(trxOff.nro_caj_ca)-1]='\0';
    trxOff.cod_tar   [sizeof(trxOff.cod_tar)   -1]='\0';
	trxOff.cod_est   [sizeof(trxOff.cod_est)   -1]='\0';
	trxOff.nro_trx   [sizeof(trxOff.nro_trx)   -1]='\0';

    /* Busca en BD una transaccion offline */
    LogAlarm.Put(0, "TrxOff: Lee offline [%s] [%s] [%s] [%s]\n", trxOff.nro_caj_ca, trxOff.cod_tar, trxOff.cod_est, trxOff.nro_trx);
	ret=DBGetNextTrx(&trxOff, &iErrorBD);
    if (ret!=OK)
    {
		LogAlarm.Put( 0, "TrxOff: Retorno de recuperacion de offline:%d Errno:%d\n", ret, iErrorBD);
		EnviarMsg(orig_pid, "ERROR", 5);
		return OK; 
	}
    //LogAlarm.Put(0, "TrxOff: Rowid a enviar [%s]\n",trxOff.rowid);

	/* Obtiene datos del centro autorizador */
    LogAlarm.Put(5, "TrxOff: Obtiene codigo de centro\n");
	strcpy(data_tar.cod_tar, trxOff.cod_tar);
	ret = ObtCA(&data_tar);
	if (ret!=OK)
	{
		LogAlarm.Put(0, "TrxOff: ERROR al obtener CA. Tar:[%s]\n", trxOff.cod_tar);
		EnviarMsg(orig_pid, "ERROR", 5);
		return OK; 
	}       

	/* Verifica si la caja esta libre */
    strcpy(term_data.nro_caj, trxOff.nro_caj);
    pos_ocup = P.IsPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
    if (pos_ocup)
    {    
		/* Marca la caja como ocupada */
		ret = P.SetPosBusy(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		if (ret!=OK)
		{
			LogAlarm.Put(0, "TrxOff: ERROR al setear caja como ocupada\n");
		}
    }
    else
    {
        /* Retorna envio de caja bloqueada */
		LogAlarm.Put(0, "TrxOff: ERROR. Caja bloqueada\n");
		EnviarMsg(orig_pid, "BLOCK", 5);
		return NOOK;
    }

    /* Arma el mensaje base de acuerdo al codigo de transaccion */
	switch (atoi(trxOff.cod_trx))
	{
	case T_VENT:
		IsoMsg=new Iso_Msg(TYPE_VISA_VENTA_LOCAL);
		break;
	case T_DEVO:
		IsoMsg=new Iso_Msg(TYPE_VISA_DEVOL_LOCAL);
		break;
	case T_PAGO:
		IsoMsg=new Iso_Msg(TYPE_VISA_VENTA_LOCAL);
		sprintf(aux_str1, "%06d", OPCODE_VISA_PAGO_RESUMEN);
		IsoMsg->PutField(3, aux_str1);
		break;
	case T_DEVP:
		IsoMsg=new Iso_Msg(TYPE_VISA_DEVOL_LOCAL);
		sprintf(aux_str1, "%06d", OPCODE_VISA_DEVO_RESUMEN);
		IsoMsg->PutField(3, aux_str1);
		break;
	default: /* Tipo de transaccion desconocida */
		/* Libera la caja */
		ret = P.SetPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		if (ret != OK)
		{
			LogAlarm.Put(0, "TrxOff: ERROR en SetPosFree. CA:[%s] Emp:[%s] Caj:[%s]\n", 
							data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		}
		LogAlarm.Put(0, "TrxOff: ERROR. Mensaje desconocido\n");
		EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}

	/* Setea centro autorizador */
	IsoMsg->SetNroCA8583(data_tar.nro_ca);

	/* Arma la informacion para el heap */
    infoHeap.origPid=orig_pid;
    strncpy( infoHeap.nroSuc  , trxOff.nro_suc, sizeof(infoHeap.nroSuc  ) );
    strncpy( infoHeap.nroTerm , trxOff.nro_caj, sizeof(infoHeap.nroTerm ) );
    strncpy( infoHeap.nroTrans, trxOff.nro_tic, sizeof(infoHeap.nroTrans) );
    strncpy( infoHeap.fechaTrx, trxOff.fec_loc, sizeof(infoHeap.fechaTrx) );
    strncpy( infoHeap.codTar  , trxOff.cod_tar, sizeof(infoHeap.codTar  ) );
    strncpy( infoHeap.NroCajCa, trxOff.nro_caj_ca,sizeof(infoHeap.NroCajCa));
    strcpy ( infoHeap.Rowid,    trxOff.rowid);
    infoHeap.nroSuc  [sizeof(infoHeap.nroSuc   )-1]='\0';
    infoHeap.nroTerm [sizeof(infoHeap.nroTerm  )-1]='\0';
    infoHeap.nroTrans[sizeof(infoHeap.nroTrans )-1]='\0';
    infoHeap.fechaTrx[sizeof(infoHeap.fechaTrx )-1]='\0';
    infoHeap.codTar  [sizeof(infoHeap.codTar   )-1]='\0';
    infoHeap.NroCajCa[sizeof(infoHeap.NroCajCa )-1]='\0';   

     /* Convierte la tarjeta a standard ISO (sin espsacio y formato LLL-VAR */
    int counter=0;
    for (counter=0;counter<sizeof(trxOff.nro_tar);counter++)
    {
		if (trxOff.nro_tar[counter]<'0' || trxOff.nro_tar[counter]>'9')
		{
			break;
		} 
    }
    trxOff.nro_tar[counter]='\0';

    /* Configura datos de la terminal */
	strcpy(term_data.cod_tar, trxOff.cod_tar);
    strcpy(term_data.nro_suc, infoHeap.nroSuc);
    strcpy(term_data.nro_caj, infoHeap.nroTerm);
    strcpy(term_data.plan_sf, trxOff.plan_sf);

    /* Busca terminal en base de datos */
	ret=getDataByNT2(&term_data);
    if ( (ret!=OK) || (term_data.caj_bloq==1) )
    {
		/* Loguea error de terminal */
		LogErrTerminal.Put(0, "Fecha Hora %s", currentTimeLog() );
        LogErrTerminal.Put(0, "Caja: %s - Sucursal: %s - Tarjeta: %s - Plan: %s - Evento: TrxOff\n\n", 
							term_data.nro_caj, term_data.nro_suc, term_data.cod_tar, term_data.plan_sf);
        LogAlarm.Put(0, "TrxOff: ERROR (%d) de terminal (%s) bloqueada (%d)\n", ret, term_data.nro_caj, term_data.caj_bloq);
    
        /* Libera la caja */
		ret = P.SetPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
        if (ret != OK)
        {
             LogAlarm.Put(0, "TrxOff: ERROR en SetPosFree. CA:[%s] Emp:[%s] Caj:[%s]\n", 
								data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
        }
        EnviarMsg(orig_pid, "ERROR", 5);
        return NOOK;
    }

    /* Numero de Tarjeta */
	sprintf(aux_str1,"%02d%s",counter,trxOff.nro_tar);
    IsoMsg->PutField(2, aux_str1);

    /* Monto */
	sprintf(aux_str1,"%012ld",atol(trxOff.monto));
    IsoMsg->PutField(4, aux_str1);

	/* Fecha de transmision */
	sprintf(szFechaEnvio, currentTimestamp());
    IsoMsg->PutField(7, szFechaEnvio);

	/* Si hora operacion mayor a transmision se rechaza */
	/* Quitar si sincronizan hora los servidores        */
	switch (DBTipoProtocoloISO(trxOff.nro_ca))
	{
	case PROT_ISO_AMEX: 
		if (strcmp(trxOff.fec_loc, szFechaEnvio)>0)
		{
			LogAlarm.Put(0, "TrxOff: Ter:[%s] Trx:[%04d]\n", infoHeap.nroTerm, atoi(infoHeap.nroTrans));
			LogAlarm.Put(0, "TrxOff: ERROR fecha/hora FHoperac[%s] FHtransm[%s]\n", trxOff.fec_loc, szFechaEnvio);
			/* Libera la caja */
			ret = P.SetPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
			if (ret != OK)
			{
				LogAlarm.Put(0, "TrxOff: ERROR en SetPosFree. CA:[%s] Emp:[%s] Caj:[%s]\n", 
								data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
			}
			EnviarMsg(orig_pid, "ERROR", 5);
	        return NOOK;
		}
		break;
	default:
		break;
	}

   	/* Numero de trace */
    TraceNumber.SetNroSuc(term_data.nro_suc);
    TraceNumber.SetNroCaj(term_data.nro_caj);
    TraceNumber.SetNroCA (term_data.nro_ca );
    TraceNumber.SetCodConCie(term_data.cod_con_cie);
    strcpy(aux_str, TraceNumber);
    TraceNumber.Inc();
    IsoMsg->PutField(11, aux_str); 

	/* Hora local */
	IsoMsg->PutField(12, trxOff.fec_loc+4);
    
	/* Fecha local */
	IsoMsg->PutField(13, trxOff.fec_loc);
    
	/* Fecha de expiracion */
	IsoMsg->PutField(14, trxOff.fec_ven);
    
	/* Fecha de captura */
	switch (DBTipoProtocoloISO(trxOff.nro_ca))
	{
	case PROT_ISO_AMEX:
		break;
	default:
		IsoMsg->PutField(17, trxOff.fec_loc);
		break;
	}
    
	/* Modo de ingreso */
	IsoMsg->PutField(22, trxOff.mod_ing );
		
	/* Codigo de red */
    IsoMsg->PutField(24, term_data.cod_red);
    
	/* Codigo de condicion */
	IsoMsg->PutField(25, "00" );

	/* Track 2 si ingreso fue por banda */
	switch (DBTipoProtocoloISO(trxOff.nro_ca))
	{
	case PROT_ISO_AMEX:
		break;
	default:
		if (   !strcmp(trxOff.mod_ing, "022") 
			|| !strcmp(trxOff.mod_ing, "062") ) 
		{
			sprintf(aux_str1, "%02d%s", strlen(trxOff.track2), trxOff.track2);
			IsoMsg->PutField(35, aux_str1);
		}
		break;
	}

	/* Codigo de autorizacion */
	sprintf(aux_str1, "%s", trxOff.cod_aut);
	switch (DBTipoProtocoloISO(trxOff.nro_ca))
	{
	case PROT_ISO_AMEX:
		if( (atoi(trxOff.cod_trx)==T_DEVO) || (atoi(trxOff.cod_trx)==T_DEVP) )
		{
			if (atoi(trxOff.mod_env)==T_OFLI)
			{
				sprintf(aux_str1, "      "); // Devolucion offline Amex
			}
		}
		break;
	default:
		break;
	}
	IsoMsg->PutField(38, aux_str1);

	/* Terminal centro autorizador */
    IsoMsg->PutField(41, term_data.nro_caj_ca);

	/* Comercio centro autorizador */	
    sprintf(aux_str1,"%-15s",term_data.nro_com);
    IsoMsg->PutField(42, aux_str1);

	/* #37322 Cuotas articulos nacionales */
	iNroCuotas = ( term_data.plan_esp > 0 ) ? term_data.plan_esp : atoi(trxOff.nro_cuo) ;
	/* Campo Cuotas */
	sprintf(aux_str1,"003%1.1s%2.2d",trxOff.plan_iso, iNroCuotas);
	if( (atoi(trxOff.cod_trx)==T_DEVO) || (atoi(trxOff.cod_trx)==T_DEVP) )
    {
		if(useCampCuot(trxOff.nro_ca)==1)
		{
			sprintf(aux_str1, "013%1.1s%02d%04d%6s", 
						trxOff.plan_iso, iNroCuotas, atoi(trxOff.nro_tic_ori), trxOff.fec_ori);
		}
    }
	/* Compras AMEX de contado no se envia campo 48 */
	switch (DBTipoProtocoloISO(trxOff.nro_ca))
	{
	case PROT_ISO_AMEX: 
		if (strcmp(aux_str1, "003001")==0) 
		{
			memset(aux_str1, 0, sizeof(aux_str1));
		}
		break;
	default:
		break;
	}
	/* Agrega campo */
	if ( strlen(aux_str1) > 0 )
	{
		IsoMsg->PutField(48, aux_str1);
	}

	/* Codigo de moneda */
	IsoMsg->PutField(49, trxOff.cod_mon );

	/* Fecha de diferimiento (si no es devolucion) */
	if (term_data.dias_dif > 0)
	{
		if( (atoi(trxOff.cod_trx)!=T_DEVO) && (atoi(trxOff.cod_trx)!=T_DEVP) )
		{
			char szFechaDif[6+1];
			if (getFechaDif(trxOff.fec_trx, term_data.dias_dif, szFechaDif)==0)
			{
				ret = strlen(CAMPO_FECHA_DIFE) + strlen(szFechaDif);
				sprintf(aux_str1, "%03d%s%s", ret, CAMPO_FECHA_DIFE, szFechaDif);
				ret = IsoMsg->PutField(59, aux_str1);
				LogAlarm.Put(10, "TrxOff: Campo 59:[%s] Ret:[%d]\n", aux_str1, ret);
			}
		}
	}

    /* Numero de ticket */
	sprintf(aux_str1,"004%04d", atoi(trxOff.nro_tic));
    IsoMsg->PutField(62, aux_str1 );

    LogAlarm.Put(0, "TrxOff: Emp:[%s] Suc:[%s] Ter:[%s] Trx:[%04d] Rowid:[%s]\n", 
						term_data.nro_suc, term_data.nro_caj_sf, infoHeap.nroTerm, 
						atoi(infoHeap.nroTrans), trxOff.rowid);

	/* Arma clave para el heap */
    sprintf(idHeap, "%2.2s%3.3s%5.5s%8.8s", term_data.nro_ca, term_data.nro_suc, term_data.nro_caj, IsoMsg->GetField(11));

    /* Pone datos en el heap */
    LogAlarm.Put(5, "TrxOff: Pone datos en el Heap\n");
	ret=Heap.PutData(idHeap,(char *)&infoHeap, sizeof(infoHeap));
	if (ret==NOOK)
	{
		LogAlarm.Put(0, "TrxOff: ERROR (%d) al insertar en Heap. Clave:[%s]\n", Heap.GetErrno(), idHeap);

		/* Libera la caja */
		ret = P.SetPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		if (ret != OK)
		{
			LogAlarm.Put(0, "TrxOff: ERROR en SetPosFree. CA:[%s] Emp:[%s] Caj:[%s]\n", 
								data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		}
        EnviarMsg(orig_pid, "ERROR", 5);
		return NOOK;
	}

    /* Carga estructura para actualizar la base de datos */
	strncpy( trxPk.nroSuc  , trxOff.nro_suc, sizeof(trxPk.nroSuc  ) );
    strncpy( trxPk.nroTerm , trxOff.nro_caj, sizeof(trxPk.nroTerm ) );
    strncpy( trxPk.nroTrans, trxOff.nro_tic, sizeof(trxPk.nroTrans) );
    strncpy( trxPk.fechaTrx, trxOff.fec_loc, sizeof(trxPk.fechaTrx) );
    strncpy( trxPk.rowid   , trxOff.rowid  , sizeof(trxPk.rowid   ) );

    /* Carga estructura para actualizar la base de datos */
	strncpy(InfoEnvio.cod_est, "01", sizeof(InfoEnvio.cod_est ));
    strncpy(InfoEnvio.fec_env, szFechaEnvio, sizeof(InfoEnvio.fec_env ));
    strncpy(InfoEnvio.nro_lot, "0000", sizeof(InfoEnvio.nro_lot));
    strncpy(InfoEnvio.nro_trc, IsoMsg->GetField(11), sizeof(InfoEnvio.nro_trc));

	/* Actualiza la base de datos */
    ret=DBUpdEnvio(trxPk , InfoEnvio);
    LogAlarm.Put(0, "TrxOff: Actualiza informacion de Envio. Retorno:%d\n", ret);

    /* Registra en cola de timeout */
	strcpy(aux_str, IsoMsg->GetField(11));
    Cfg.GetItem("TimeOutDaemon", "MsgTimeOut1", aux_str1);
	LogAlarm.Put(0, "TrxOff: Timeout ID Trace [%s]\n", idHeap);
    ret=timeout_queue.SetTimeOut(idHeap, atoi(aux_str1), GetType(), "");
    if (ret==NOOK)
    {
        LogAlarm.Put(0, "TrxOff: ERROR (%d) al registrar en TOQ\n",ret);

		/* Libera la caja */
		ret = P.SetPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		if (ret != OK)
		{
			LogAlarm.Put(0, "TrxOff: ERROR en SetPosFree. CA:[%s] Emp:[%s] Caj:[%s]\n", 
							data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
		}

		/* Retira del heap */
		ret=Heap.GetData(idHeap,(char *)&infoHeap, sizeof(infoHeap));
		if (ret == NOOK)
		{
			LogAlarm.Put( 0, "TrxOff: ERROR (%d) al obtener del heap\n", Heap.GetErrno());
		}
		
		/* Envia respuesta */
		EnviarMsg(orig_pid, "ERROR", 5);
		
		return NOOK;
    }

    /* Aplana el mensaje */
    len=IsoMsg->GetMsgString(msg_str);

	/* Loguea el mensaje */
	for (iCont=0; iCont<64; iCont++)
	{
		if (IsoMsg->ChkField(iCont))
		{
			LogAlarm.Put(5, "TrxOff: Campo %02d: Valor:[%s]\n", iCont, IsoMsg->GetField(iCont) );
		}
	}

    /* Envia el mensaje a X25 */
	LogAlarm.Put(0, "TrxOff: Envia a X.25. CAut [%s]\n", term_data.nro_ca);
    ret=XQueue.SendMsg(atoi(term_data.nro_ca)+1, msg_str, len);
    if (ret!=OK)
    {
        LogAlarm.Put(0, "TrxOff: ERROR en Envio X.25(%d)\n", XQueue.GetErrno());

		/* Libera la caja */
        ret = P.SetPosFree(data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
        if (ret != OK)
        {
             LogAlarm.Put(0, "TrxOff: ERROR en SetPosFree. CA:[%s] Emp:[%s] Caj:[%s]\n", 
								data_tar.nro_ca, trxOff.nro_suc, trxOff.nro_caj);
        }
        
		/* Envia respuesta */
		EnviarMsg(orig_pid, "ERROR", 5);

        return NOOK;
    }
    return OK;
}