Example #1
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;
}
Example #2
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;
}