<?php
class finance
{
	private $error   = true; 
	public $Type   = '';
	private $MaxMontant   = 500000;
	private $Maintenance   = false;
	private $SessionMaxTime = 13600;
	private $Production = 1;
	private $IsPayment = false;
	private $Momo = 0;	
	###########################################################
	
	function __construct($token=array())
	{
		global $sgbd, $log_sgdb;//SGBD
		$this->ldb = $log_sgdb;
		$this->db = $sgbd;
		set_time_limit(300);
		$this->IsPayment = false;
		if(!empty($token)) 
		{
			$this->agent_id = $token->agent_id;
			$this->MerchantKey = $token->MerchantKey;
		}
		$this->Generic = "PIX";
		//PIM : Pay In Mobile
		

	}
	public function setData($data)
	{
		$this->receiveData = $data;
	}
	private function getGlobalParameters()
	{
		global $sgbd;
		$params = $sgbd->liste("select * from parametres where etat=1");
		
		//Configration globale de l'application
		
	}
	
	function getUID()
	{
		$file = @file_get_contents("https://www.uuidgenerator.net/api/version4", true);
		if(!empty($file)) return trim($file);
	}
	function setProduction()
	{
		$this->Production = 1;
		$this->Simulation = 0;
	}
	function setSimulation()
	{
		$this->Production = 0;
		$this->Simulation = 1;
	}
	function local_json($result,$agent_id="")
	{
		
		if($result['error'])
		{
			$status = strtoupper($result['error']['status']);
			$nerror = array();
			if(!empty($this->IDTransaction))
			{
				$nerror['transaction_id'] = $this->IDTransaction;
				$nerror['order_id'] = $this->receiveData['order_id'];
				$nerror['reference_id'] = $this->receiveData['reference_id'];
				$nerror['phone_number'] = $this->receiveData['phone_number'];
				$nerror['amount'] = $this->receiveData['amount'];
				$nerror['fees'] = $this->receiveData['fees'];
				$nerror['taxes'] = $this->receiveData['taxes'];
				$nerror['amount_total'] = $this->receiveData['amount_total'];
				$nerror['status'] = $status;
			}
			$result['error']= array_merge($nerror,$result['error']);
		}
		elseif($result['reponse'])
		{
			$status = strtoupper($result['reponse']['status']);
			$result['reponse']['amount'] = $this->receiveData['amount'];
			$result['reponse']['phone_number'] = $this->receiveData['phone_number'];
			$result['reponse']['order_id'] = $this->receiveData['order_id'];
			$result['reponse']['reference_id'] = $this->receiveData['reference_id'];
			$result['reponse']['status'] = $status;
		}
		
		if(!empty($status))
		{
			$query = "UPDATE `transactions` 
			SET 
				`status` = '".$status."'
			WHERE transaction_id=  '".$this->IDTransaction."'";
			
			$this->db->query($query);
		}
		
		local_json($result,$this->agent_id);
	}
	function getProvider($provider="")// Appele le fournisseur du service
	{
		if($this->receiveData['amount']<40)
		{
			$error['code']=404;
			$error['status'] ="FAILED";
			$error['reason'] ="the amount must be greater than 40 XAF";
			$result['error']=$error;
			$this->local_json($result);
		}
		
		global $sgbd,$gprovider;
		$cash = array('orange','mtn');
		
		$GLOBALS['provider']= $provider;
		if(empty($this->receiveData['country']))
		{
			return $this->SetError(507,"Unable to identify country");
		}
		if(empty($this->receiveData['operator']))
		{
			return $this->SetError(507,"Unable to identify operator");
		}
		
		$this->Country = $this->receiveData['country'];


		//retrouver le service en fonction de l'operateur
		
		switch($this->TypeService)
		{
			case 'pay':
			case 'cash':
				
				if(empty($this->receiveData['phone_number']) or empty($this->receiveData['country']))
				{
					$error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="Ressource unavaible";
					$result['error']=$error;
					$this->local_json($result,$this->agent_id);
				}
				/*$phone = getphone($this->receiveData['phone_number'],$this->receiveData['country']);
				
				
		
				$this->receiveData['phone_number'] =*/
				
				if(!$phone = getphonedata($this->receiveData['phone_number'],$this->receiveData['country']))
				{
					$error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="invalid phone number format for this country";
					$result['error']=$error;
					
					$this->local_json($result,$this->agent_id);
				}    
				$this->receiveData['country'] = strtoupper($this->receiveData['country']);
				$msisdn = $phone['international_phone'];
				$this->receiveData['phone_number']=
				$this->receiveData['international_phone']= $phone['international_phone'];
				$this->receiveData['national_phone']= $phone['national_phone'];

				$this->Numero = $msisdn;
				
				if(!empty($this->receiveData['operator']))
				{
					$provider = $this->receiveData['operator'];
					
				}
				
			break;
			case 'banque':
			case 'bank':
				$provider = "bank";
			break;
			
			default:
					$error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="Ce type de transaction n'est pas pris en compte";
					$result['error']=$error;
					$this->local_json($result,$this->agent_id);
			
			
		}
		
		$bank = $this->receiveData['account_bank'];
		$query = "select * from customers_services where service_code ='".$provider."' and country='".strtoupper($this->Country)."' and agent_id = '".$this->agent_id."'";
		
		$this->Service  = $sgbd->query($query)->row_array();
		$query = "select * from country_services where service_code ='".$provider."' and country='".strtoupper($this->Country)."'";
		
		$this->GService  = $sgbd->query($query)->row_array();
		if(empty($this->Service) and empty($this->GService))
		{
			$error['code']=404;
			$error['status'] ="FAILED";
			$error['reason'] ="Ce operateur de transaction n'est pas disponible";
			$result['error']=$error;
			$this->local_json($result,$this->agent_id);
		}
		
		if(empty($this->Service['payin']) or strtoupper($this->Service['payin'])=='NONE' ) $this->Service['payin']=$this->GService['payin'];
		if(empty($this->Service['payout']) or strtoupper($this->Service['payout'])=='NONE') $this->Service['payout']=$this->GService['payout'];
		if(empty($this->Service['bankin']) or strtoupper($this->Service['bankin'])=='NONE') $this->Service['bankin']=$this->GService['bankin'];
        if(empty($this->Service['service_code']))  $this->Service['service_code'] = $this->GService['service_code'];;

		switch(strtolower($this->Type))
		{
			case 'payout':
				$this->Service['provider_code']= $this->Service['payout'];
			break;
			case 'payin':
				$this->Service['provider_code']= $this->Service['payin'];
			break;
			case 'bankin':
				$this->Service['provider_code']= $this->Service['bankin'];
			break;
			default:
					$error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="Ce type de transaction n'est pas pris en compte";
					$result['error']=$error;
					$this->local_json($result,$this->agent_id);
			
		}
		

		if(empty($this->Service))
		{
			return $this->setError(511,"This operator code is not valid or activated on the platform.","The `$provider` code service does not exist.");
		}
		else
		{
			$this->Montant = $this->receiveData['amount'];
			$this->Reference = $this->receiveData['reference_id'];
			$this->order_id = $this->receiveData['order_id'];

			if(!empty($this->receiveData['merchant_key']))
			{
				if($this->receiveData['merchant_key']!=$this->MerchantKey)
				{
					//return $this->setError(502,"Invalid credentials merchant_key ".$this->receiveData['merchant_key']."");
				}
			}
			//Verification de la reference
			if(!empty($this->Reference))
			{
				$query = "select reference_id from transactions where agent_id='".$this->agent_id."' and reference_id ='".$this->Reference."'";
				
				$vref = $sgbd->query($query)->row_array();
				
				if(!empty($vref))
				{
					//return $this->setError(502,"Reference ".$this->Reference." is used ");
				}
			}
			if(!empty($this->order_id))
			{
				$query = "select order_id from transactions where agent_id='".$this->agent_id."' and order_id ='".$this->order_id."'";
				
				$vref = $sgbd->query($query)->row_array();
				
				if(!empty($vref))
				{
					return $this->setError(502,"Order ID ".$this->order_id." is used ");
				}
			}
			
			switch($this->Type)
			{
				case 'payin':
					$this->getPayeur($this->Service['payin']);
				break;
				case 'payout':
					$this->getPayeur($this->Service['payout']);
				break;
				case 'bankin':
					$this->getPayeur($this->Service['bankin']);
				break;
				default:
				$error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="Ce type de transaction n'est pas pris en compte";
					$result['error']=$error;
					$this->local_json($result,$this->agent_id);
			}
			
			if(!empty($this->Provider))
			{
				$this->Provider->Data = $this->receiveData;
			}
			
			return true;
		}
		
		
	}
	function getPayeur($Provider)
	{

		$Provider = strtolower($Provider);
		
	    global $gprovider;
		$gprovider = $Provider;
		
		if(empty($gprovider))
		{
                    $error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="Ce service n'a pas d'agregateur défini";
					$this->Return['error']=$error;
		}
		
		$this->receiveData['provider_code'] = $Provider;
		
		switch($Provider)
		{
			case 'viralpay':
				return false;				
			break;
			case 'hub2':
				uses_class('hub2');
				$paye = new hub2();				
			break;
			case 'mtncameroon':
				uses_class('mtnpay');
				$paye = new mtnpay();			
			break;
			case 'mtnci':
				uses_class('mtnci');
				$paye = new mtnci();			
			break;
			case 'mtn':
				uses_class('mtn');
				$paye = new mtn();			
			break;
			case 'fedapay':
				uses_class('fedapay');
				$paye = new fedapay;
				
			break;
			case 'intouch':
				uses_class('intouch');
				$paye = new intouch;
			break;
			case 'bizao':
				uses_class('bizao');
				$paye = new bizao;
			break;
			case 'kikiapay':
				uses_class('kikiapay');
				$paye = new kikiapay;
			break;
			case 'paydyuna':
				uses_class('paydyuna');
				$paye = new paydyuna;				
			break;
			case 'pakhpay':
				uses_class('pakhpay');
				$paye = new pakhpay;				
			break;
			case 'orange':
				uses_class('orange');
				$paye = new orange;
			break;
			case 'orangeci':
				uses_class('orangeci');
				$paye = new orangeci;
			break;
			case 'paydunya':
				uses_class('paydunya');
				$paye = new paydunya;
			break;
			case 'iwomipay':
				uses_class('iwomipay');
				$paye = new iwomipay;
			break;
			case 'sandbox':
				uses_class('sandbox');
				$paye = new sandbox;
			break;
			case 'pixelinnov':
				uses_class('pixelinnov');
				$paye = new pixelinnov;
			break;
			case 'fedapay':
				uses_class('fedapay');
				$paye = new fedapay;
			break;
			default: 
				/*uses_class('danol');
				$paye = new danol;*/
				
				$error['code']=404;
				$error['status'] ="FAILED";
				$error['reason'] ="Pas d'agregateur disponible pour ce service";
				$result['error']=$error;
				$this->Return['error']=$error;
		}
		
		
		if(!empty($paye))
		{
			$this->Provider = $paye;
			
		}			
		else  return $this->setError(502,"Unknow provider");
	}
	function getBalance($Provider='')
	{
	
		if(!empty($this->Provider))
		{
			$Provider = $this->Provider;//Fournisseur du service;
		}
		
		//Choix du fournisseur à utiliser
		$this->getPayeur($Provider);
		$paye = $this->Provider;
		
		//Choix du mode d'execution (Live/Sanbox)
		if($this->Production) $paye->setProduction();
		else $paye->setSimulation();
		
		//Obtention de la balance correspondant au fournisseur choisi
		if(!empty($paye)) 
		{
			$paye->getBalance();
			$return= $paye->Solde;
		}
		else $return['balance']= "";
		
		return $return;
	}
	
	
	function getFacture()
	{	
		global $sgbd;
		$query = "select * from factures where service_code ='".$this->receiveData['provider']."' and numerofacture ='".$this->receiveData['billid']."' limit 1";
		$facture = $sgbd->query($query)->row_array();
		$data['provider'] = $facture['service_code'];
		$data['amount'] = $facture['Montant'];
		$data['billid'] = $facture['NumeroFacture'];
		$data['billdate'] = $facture['DateFacture'];
		$this->receiveData = $data;
		
	}
	
	
	function createTransaction()
	{
		global $sgbd;
		$transaction_type = 'N';
		
		
		if(strtolower($this->Type)=='payout') $transaction_type = 'D';
		elseif(strtolower($this->Type)=='payin') $transaction_type = 'C';
		

		$this->IDTransaction = $this->getIDTransaction();
		$query = "INSERT INTO `transactions`(`service_code`,`provider_code`,`transaction_type`,`transaction_id`, `agent_id`, `status`, `ip_address`,`date_created`,account_number,fees,fees_taxes_ttc,taxes,amount_total,compensated,provider_status,infos,details,reference_id,order_id,user_id, `date_payment`, `date_recovery` )
		VALUES ('".$this->Service['service_code']."','".$this->Service['provider_code']."','".$transaction_type."','".$this->IDTransaction."', '".$this->agent_id."', 'Initiate','".get_ip()."','".datetime()."','','0','0','0','0','0','','','','','',0, '0000-00-00 00:00:00','0000-00-00 00:00:00' )";
	
		$sgbd->query($query);
		
		
	}
	###########################################################
	#		SAUVEGARDE DE LA TRANSACTION EN COURS
	###########################################################
	function getCompte()
	{
		global $sgbd;
		$type = strtoupper($this->Type);
		
		switch($type)
		{
			case 'BANKIN':
					$this->account_type = 'PAYOUT';
			break;
			case 'PAYOUT':
				$this->account_type = 'PAYOUT';
			break;
			case 'PAYIN':
				$this->account_type = 'PAYIN';
			break;
			default:
					$error['code']=404;
					$error['status'] ="FAILED";
					$error['reason'] ="Bank transfer disponible";
					$result['error']=$error;
					$this->local_json($result,$this->agent_id);
		}

		//verification, creation identification du compte
		
		$query =  "select * from country where lower(code) ='".strtolower($this->receiveData['country'])."'";
		
		$country = $sgbd->query("select * from country where lower(code) ='".strtolower($this->receiveData['country'])."'")->row_array();
		
		if(empty($country))
		{
			$error['code']=404;
			$error['status'] ="FAILED";
			$error['reason'] ="invalid iso country code ".$this->receiveData['country']." ";
			$return['error']=$error;
			$this->local_json($return,$this->agent_id);
		}
		$this->Taxes = $country['taxes'];
		
		if($country['currency']!=$this->receiveData['currency'])
		{
			$error['code']=404;
			$error['status'] ="FAILED";
			$error['reason'] ="Invalid currency ".$this->receiveData['currency']." for country ".$country['name'];
			$return['error']=$error;
			$this->local_json($return,$this->agent_id);
		}
		
		$this->receiveData['currency'] = strtoupper($this->receiveData['currency']);
		$this->receiveData['country']= strtolower($this->receiveData['country']);
		$query = "select * from customers_accounts where agent_id = '".$this->agent_id."' and account_type='".$this->account_type."' and currency='".$this->receiveData['currency']."' and  country = '".strtoupper($this->receiveData['country'])."'";
		
		$compte = $sgbd->query($query)->row_array();
		
		if(empty($compte))
		{			
			$numCompte = strtoupper($this->receiveData['country']).'-'.$this->account_type.'-'.date('w').random_number(12);
			$query = "INSERT INTO `customers_accounts`( `account_number`, `agent_id`, `account_type`, `country`, `currency`, `date_created`, `login_created`, `date_updated`) VALUES
										   ('".$numCompte."','".$this->agent_id."','".$this->account_type."','".$this->receiveData['country']."','".$this->receiveData['currency']."','".datetime()."','','".datetime()."')";
			$sgbd->query($query);
			$query = "select * from customers_accounts where agent_id = '".$this->agent_id."' and account_type='".$this->account_type."' and currency='".$this->receiveData['currency']."' and  country = '".strtoupper($this->receiveData['country'])."'";
			$compte = $sgbd->query($query)->row_array();
		}
		$this->account_number = $compte['account_number'];
		$this->Compte = $compte;

		#

		uses_class('compte');
		$this->AgentCompte = new compte($this->account_number);
		
		$this->AgentCompte->load();
		
		$this->AgentCompte->available($this->Service['service_code']);
		
		
		$this->Commission = $this->AgentCompte->Commission; 
		
	}
	function soldeVerification()
	{
		$this->Total = $this->Montant+$this->Fees;
		
		if($this->Total>$this->AgentCompte->balance_available)
		{
			
			//$error = $this->Return['reponse'];
			$error['code']=404;
			$error['status'] ="FAILED";
			$error['reason'] ="Your balance ".$this->account_type." (".$this->AgentCompte->balance_available.") is insufficient for ".$this->Total." ".$this->receiveData['currency']." amount";
			$return['error']=$error;
			$this->local_json($return,$this->agent_id);
		}
	}
	function saveTransaction()
	{
		global $sgbd; 
		if(empty($this->status)) $this->status = 'PENDING';
		$this->status = strtoupper($this->status); 
		$this->ProviderStatut = strtoupper($this->Return['reponse']['status']); 
		
		
		
		if(empty($this->status)) $this->status = $this->ProviderStatut;
		$this->Return['reponse']['amount_total']= $this->receiveData['amount_total'];
		$this->Return['reponse']['date_created']= datetime();
		//$this->Return['reponse'] = loadTransaction($this->Return['reponse']);
		
		$Infos = json_encode($this->Return['reponse']);//Infos;
		
		
		$query = "UPDATE `transactions` 
					SET 
						`Infos` = '".$Infos."',
						`status` = '".$this->status."'
					WHERE transaction_id=  '".$this->IDTransaction."'";
		
		$sgbd->query($query);
		$this->Return['reponse']['status'] = strtoupper($this->status);

		unset($this->Return['reponse']['return_url']);
		unset($this->Return['reponse']['cancel_url']);
		unset($this->Return['reponse']['notify_url']);	 
		unset($this->Return['reponse']['provider_message']);	
		unset($this->Return['reponse']['uid']);	
		
		$return = array();
		if(!empty($this->Return['error']))
		{
			$return['error']= $this->Return['error'];
			unset($return['error']['provider_error']);
			unset($return['error']['provider_code']);
			$return['error'] = $this->rangedata($return['error']);
			$this->local_json($return,$this->agent_id);
		}
		elseif(!empty($this->Return['reponse']))
		{
			$return['data']= $this->Return['reponse'];
			unset($return['data']['provider_error']);
			unset($return['data']['provider_code']);
			$return['data'] = $this->rangedata($return['data']);
			$this->local_json($return,$this->agent_id);
			
		}
		
			
		
	}
	function bulkTransaction()
	{
		global $sgbd;
		if(empty($this->status)) $this->status = 'PENDING';
		$this->status = strtoupper($this->status); 
		$this->ProviderStatut = strtoupper($this->Return['reponse']['status']); 
		
		
		
		if(empty($this->status)) $this->status = $this->ProviderStatut;
		$this->Return['reponse']['amount_total']= $this->receiveData['amount_total'];
		$this->Return['reponse']['date_created']= datetime();
		//$this->Return['reponse'] = loadTransaction($this->Return['reponse']);
		
		$Infos = json_encode($this->Return['reponse']);//Infos;
		
		
		$query = "UPDATE `transactions` 
					SET 
						`Infos` = '".$Infos."',
						`status` = '".$this->status."'
					WHERE transaction_id=  '".$this->IDTransaction."'";
		
		$sgbd->query($query);
		$this->Return['reponse']['status'] = strtoupper($this->status);

		unset($this->Return['reponse']['return_url']);
		unset($this->Return['reponse']['cancel_url']);
		unset($this->Return['reponse']['notify_url']);	 
		unset($this->Return['reponse']['provider_message']);	
		unset($this->Return['reponse']['uid']);	
		$return = array();
		if(!empty($this->Return['error']))
		{
			$this->Bulks[]=$this->Return['error'];
		}
		elseif(!empty($this->Return['reponse']))
		{
			$this->Bulks[]=$this->Return['reponse'];
		}
		
	}
	function beginTransaction()
	{
		
		if(!empty($this->receiveData['order_id'])) $this->Return['reponse']['order_id'] = $this->receiveData['order_id'];
		if(!empty($this->receiveData['reference_id'])) $this->Return['reponse']['reference_id'] = $this->receiveData['reference_id'];
		if(!empty($this->receiveData['country'])) $this->Return['reponse']['country'] = $this->receiveData['country'];
		if(!empty($this->receiveData['currency'])) $this->Return['reponse']['currency'] = $this->receiveData['currency'];
		if(!empty($this->receiveData['lang'])) $this->Return['reponse']['lang'] = $this->receiveData['lang'];
		if(!empty($this->receiveData['operator'])) $this->Return['reponse']['operator'] = $this->receiveData['operator'];
		$this->Return['reponse']['transaction_id'] = $this->IDTransaction;
		if(!empty($this->Return['error'])) 
		{
			$status = $this->Return['error']['status'];
		}
		elseif(!empty($this->Return['reponse'])) 
		{
			
			if(empty($this->Montant))
			{
				$error['code']=404;
				$error['status'] ="FAILED";
				$error['reason'] ="Invalid currency ".$this->receiveData['currency']." for country ".$country['Nom'];
				$return['error']=$error;
				$this->local_json($return,$this->agent_id);
			}

			
			
			$this->receiveData['transaction_id'] = $this->transaction_id;
			if(!empty($this->receiveData['order_id'])) $this->Return['reponse']['order_id'] = $this->receiveData['order_id'];
			if(!empty($this->receiveData['reference_id'])) $this->Return['reponse']['reference_id'] = $this->receiveData['reference_id'];
			if(!empty($this->receiveData['country'])) $this->Return['reponse']['country'] = $this->receiveData['country'];
			if(!empty($this->receiveData['currency'])) $this->Return['reponse']['currency'] = $this->receiveData['currency'];
			if(!empty($this->receiveData['lang'])) $this->Return['reponse']['lang'] = $this->receiveData['lang'];
			if(!empty($this->receiveData['return_url'])) $this->Return['reponse']['return_url'] = $this->receiveData['return_url'];
			if(!empty($this->receiveData['cancel_url'])) $this->Return['reponse']['cancel_url'] = $this->receiveData['cancel_url'];
			if(!empty($this->receiveData['notify_url'])) $this->Return['reponse']['notify_url'] = $this->receiveData['notify_url'];
			if(!empty($this->receiveData['notif_url'])) $this->Return['reponse']['notify_url'] = $this->receiveData['notif_url'];
		}
		else $status = "PENDING";
		
		if(empty($this->UID)) $this->UID =getUID() ;
		$this->status = $status;
		global $sgbd;
		
		
		if(empty($this->Details))
		{
			if(!empty($this->receiveData)) $this->Details = $this->receiveData;
			else $Details = "";
		} 
		else
		{
			if(is_array($this->Details)) $this->Details = json_encode($this->Details);
			$Details = addslashes($this->Details);
		}

		
		if(empty($this->Total)) $this->Total = $this->Montant;
		else
		{
			$this->Frais = $this->Total-$this->Montant;
			if(!empty($this->Frais) and !empty($this->Return['reponse'])) $this->Return['reponse']['fees']= $this->Frais;
		}
		if(empty($this->Frais)) $this->Frais = 0;
		
		
		if(empty($this->status)) $this->status = 'PENDING';
		$this->status = strtoupper($this->status); 
		
		$this->getCompte();
		
		if($Commission = $this->getCommission($montant))
		{
			
			if($Commission['fees']>0) $this->Frais = $Commission['fees'];
		
			$this->receiveData['fees'] = 
			$this->Return['reponse']['fees']=$Commission['fees'];

			$this->receiveData['taxes'] = 
			$this->Return['reponse']['taxes']=$Commission['taxes'];

			$this->receiveData['amount'] = 
			$this->Return['reponse']['amount']= $Commission['amount'];

			$this->receiveData['amount_total'] =
			$this->Return['reponse']['amount_total']= $Commission['amount_total'];

			$this->receiveData['fees_taxes_ttc'] =
			$this->Return['reponse']['fees_taxes_ttc']= $Commission['fees_taxes_ttc'];
			
		}

		

		$Infos = json_encode($this->Return['reponse']);
		
		$query = "UPDATE `transactions` 
		SET 
			  `amount` = '".$this->receiveData['amount']."',
			`transaction_type` = '".addslashes(iso_encode($this->TypeTransaction))."',
			`fees` = '".$this->receiveData['fees']."',
			`infos` = '',
			`taxes` = '".$this->receiveData['taxes']."',
			`amount_total` = '".$this->receiveData['amount_total']."',
			`account_number` = '".$this->account_number."',
			`recipient_number` = '".$this->receiveData['international_phone']."',
			`status` = '".$this->status."',
			`date_created` = '".datetime()."',
			`fees_taxes_ttc` = '".$this->receiveData['fees_taxes_ttc']."',
			`uuid` = '".$this->UID."',
			`reference_id` = '".$this->receiveData['reference_id']."',
			`order_id` = '".$this->receiveData['order_id']."',
			`details` = '".$Details."',
			`infos` = '".$Infos."'
			
			
		  WHERE 

			  transaction_id=  '".$this->IDTransaction."'
			  ";
			 
		$sgbd->query($query); 

		//Conditions du payout()
		if(strtoupper($this->Type)=='PAYOUT')
		{
			if($this->account_type=='PAYOUT')
			{
				$this->soldeVerification();
			}
		}
		
	}
	function uniqueTransaction()
	{
		global $sgbd;
		
		$same_number_limit = date('Y-m-d H:i:s',strtotime(datetime())-1*40);//limite d'une transaction vers le même numero
		$same_number_amount_limit = date('Y-m-d',strtotime(datetime())-5*60);//limite d'une transaction vers le même numero
		$query = "select transaction_id from transactions where (recipient_number = '".$this->receiveData['international_phone']."' and date_created>'".$same_number_limit."')";
		
		$verif = $this->db->query($query)->row_array();
		
		$verif = "";
		if(!empty($verif))
		{
			$error['code']=404;
			$error['status'] ="FAILED";
			$error['reason'] ="Busy phone number";
			$return['error']=$error;
			$this->local_json($return,$this->agent_id);
		}
		
		//Créer un numéro de transaction unique qui expirera après 5 min sans transaction effectuée
		$this->createTransaction();
		
	}
	function Depot()//transfert de credit 
	{
		$this->Generic = "POM".date('yd');
		$this->TypeTransaction = "PAY OUT";
		$this->uniqueTransaction(); 
		$this->dataProvider();
		$this->beginTransaction();
		$this->Provider->Depot();
		$this->mergeResult($this->Provider->Return);
		$this->saveTransaction();
		
	}

	function Bulkout()//transfert de credit 
	{
		$this->Generic = "POM".date('yd');
		$this->TypeTransaction = "PAY OUT";
		$this->uniqueTransaction();
		if(!empty($this->Provider))
		{
			$this->dataProvider();
			$this->beginTransaction();
			$this->Provider->Depot();
			$this->mergeResult($this->Provider->Return);
			$this->bulkTransaction();
		}
		//else print_r($this->Return);
		
		
	}
	###########################################################
	#		VERIFICATION DU SOLDE CLIENT
	###########################################################
	function isService($numero,$montant,$service)//Verifie que l'opération est possible et fait le récapitulatif à afficher 
	{
		global $sgbd;
		
		//Charger le service
		$cservice = $sgbd->query("select * from webservices where idservice ='".$service."'");

		//Vérifier le format du numéro
		
		//Vérifier le format du montant
		
		//Calculer les commissions
		$this->Commission = $this->getCommission($montant,'OUT');
		
		
		//Recapitulatif de la transaction 
		$this->Return['service']= $cservice['Nom'];
		$this->Return['montant']= $montant;
		$this->Return['frais']= (($montant * $this->Commission['fraisvar'])/100 + $this->Commission['fraisfixe']);
		$this->Return['amount_total']= $montant + $this->Return['frais']; 
	}
	
	###########################################################
	#		MODULE DE RETRAIT D'ARGENT
	###########################################################
	function Retrait()//transfert de credit 
	{
		$this->Generic = "PIM".date('yd');
		
		$this->TypeTransaction = "PAYIN";

		$this->uniqueTransaction();		
		
		$this->dataProvider();
		$this->beginTransaction();
		$this->Provider->setData($this->receiveData);
		global $gprovider;
		
		$this->Provider->Retrait();
		
		
		$this->mergeResult($this->Provider->Return);
		
		$this->saveTransaction();
		
		
	}

	function callback($url,$data)
	{
		$headers = getallheaders();
		
		global $sgbd;
		
		if(empty($data['transaction_id'])) $data['transaction_id']= $data['transaction_id'];

		$query = "select infos,merchant_key,transactions.date_created,transactions.date_payment as status_date,transactions.status,service_code,amount_total from transactions 
		left join users on users.agent_id = transactions.agent_id 
		left join api_users on api_users.user_id = users.user_id where transactions.transaction_id = '".$data['transaction_id']."' ";
	   
		$info = $sgbd->query($query)->row_array();
		$info['status'] = strtoupper($info['status']);
		
		
		if($info['status']!='SUCCESS' and $info['status']!='FAILED') return false;
		
		if(empty($info)) return false;
		 $data = json_decode($info['infos'],true);
		 
		unset($data['notif_url']);
		unset($data['notify_url']);
		unset($data['cancel_url']);
		unset($data['return_url']);
		
		
		
		 $data['date_created'] = $info['date_created'];
		 $data['status_date'] = $info['status_date'];
		
		if(empty($data['provider_code']))$data['provider_code'] = $info['service_code'];
		$data['country'] = strtoupper($data['country']);
		$data['status'] = strtoupper($info['status']);
		
		
		// Ecart de 1 min entre les callbacks
		$query = "select call_date from customers_callbacks_logs where transaction_id = '".$data['transaction_id']."' order by call_date DESC";
		global $log_sgdb;
		$last = $log_sgdb->query($query)->row_array();
		
		$delta = 2500;
		if(!empty($last))
		{
			$delta = strtotime(datetime())-strtotime($last['call_date']);
			
		}
		
		if($delta<60) return false;
		$sign = sign(json_encode($data),$data['merchant_key']);
		
		
		uses_class('curl');
		$curl = new curl;
		$curl->addHeader("Content-Type","application/json");
		$curl->addHeader('VIRALPAY_SIGN',$sign);
		$curl->setUrl($url);
		$curl->setMethode('POST');
		$curl->setData($data);
	
		$curl->make();
		
		global $log_sgdb;

		$query = "insert into customers_callbacks_logs(transaction_id,ip_address,url,data,http_status,call_date) values ('".$data['transaction_id']."','".get_ip()."','".addslashes($url)."','".addslashes(json_encode($data))."','".$curl->ErrorNumber."','".datetime()."')";

		$log_sgdb->query($query);
		return true;

	}
	
	function dataProvider()
	{
		$this->Provider->Numero = $this->Numero;
		$this->Provider->Montant = $this->Montant;
		$this->Provider->IDTransaction = $this->IDTransaction;
		$this->Provider->Reference = $this->Reference;
	}
	function mergeResult($result)
	{
		
		
		if(is_array($result['reponse']))
		{
			foreach($this->Return['reponse'] as $key=>$val)
			{
				if(empty($result[$key])) $result['reponse'][$key]= $val;
			}
			$this->Return['reponse'] = $result['reponse'];
		
		
		}
		if(is_array($result['error']))
		{
			foreach($this->Return['error'] as $key=>$val)
			{
				if(empty($result[$key])) $result['error'][$key]= $val;
			}
			$this->Return['error'] = $result['error'];
		}

	}
	
	###########################################################
	#		MODULE DE TRANSFERT BANCAIRE
	###########################################################
	function BankTransfert()//transfert de credit 
	{
		$this->Generic = "POT".date('yd');
		$this->TypeTransaction = "TRANSFERT BANCAIRE";
		$this->uniqueTransaction();	
		$this->Numero = $this->receiveData['bank_account_number'];
		$this->dataProvider();
		$this->beginTransaction();

		$this->Provider->BankTransfert();
		$this->mergeResult($this->Provider->Return);
		$this->saveVirement();
		$this->saveTransaction();
	}
	function saveVirement()//transfert de credit 
	{
		$query = "INSERT INTO `banks`( `service_code`, `NumeroClient`, `NumeroFacture`, `amount`, `DateFacture`, `Infos`, `agent_id`, `Paid`,`order_id`) 
						VALUES ('".$this->Return['reponse']['operator']."','".$this->Return['reponse']['bank_account_number']."','".$this->IDTransaction."','".$this->Return['reponse']['amount']."','".datetime()."','".json_encode($this->Return['reponse'])."','".$this->agent_id."','0','".$this->Return['reponse']['order_id']."')";
		
		$this->db->query($query);
	}
	
	
	###########################################################
	#		VERIFICATION DU RETRAIT DE FOND
	###########################################################
	function getStatus($trans)//transfert de credit 
	{
		global $sgbd;
		
		
		if(!is_array($trans))
		{
			$trans = $sgbd->query("select transactions.agent_id,transactions.account_number,transaction_id,infos,transactions.date_payment as pay_date,transactions.status,service_code,provider_code as provider_code from transactions where transaction_id = '".$trans."'")->row_array();

			$trans = json_decode($trans['infos'],true);
		}
		
		if(empty($trans['status'])) $trans['status'] = $trans['status'];
		if(strtolower($trans['status'])!='pending') return $trans['status'];

	

		//Choix du fournisseur à utiliser
		if(empty($trans['status'])) $trans['status'] = $trans['status'];
		if(empty($trans['provider_code'])) $trans['provider_code'] = $trans['provider_code'];
		$this->getPayeur($trans['provider_code']);
		
		if(empty($this->Provider)) return $trans['status'];
		
		$status = $this->Provider->getStatus($trans);
		
		$status = $this->valideTransaction($status,$trans);
		
		return $status;
	}

	###########################################################
	#		VERIFICATION DU SOLDE CLIENT
	###########################################################
	function getIDTransaction()
	{
		$code = getMatricule(14,"transactions","transaction_id",$this->Generic);
		return $code;
	}
	function rangedata($current)
	{
		$order_id = array('code','transaction_id','order_id','operator','phone_number','amount','reason','taxes','fees','fees_taxes_ttc','amount_total','currency','status','country','lang','reference_id','provider_id');
		
		$reponse = array();
		
		foreach($order_id as $ord)
		{
			if(isset($current[$ord]))
			{
				$reponse[$ord]= $current[$ord];
				unset($current[$ord]);
			}
		}
		
		$reponse = array_merge($reponse,$current);
		return $reponse;
		
	}
	###########################################################
	#		CALCUL DES COMMISSIONS
	###########################################################
	function getCommission($montant,$cash='',$service='')
	{
		$comm['fees']=0;
		$comm['taxes']=0;
		$comm['amount']= $montant;
		if(empty($montant)) $montant = $this->Montant;
		
		switch($this->account_type)
		{
			case 'PAYIN':
				if($this->Commission['commission_type_in']=='FIXED')
				{
					$comm['fees'] = $this->Commission['commission_in'];
				}
				elseif($this->Commission['commission_type_in']=='VARIABLE')
				{
					$comm['fees'] = $montant*$this->Commission['commission_in']/100;
				}

			break;
			case 'PAYOUT':
				if($this->Commission['commission_type_out']=='FIXED')
				{
					$comm['fees'] = $this->Commission['commission_out'];
				}
				elseif($this->Commission['commission_type_out']=='VARIABLE')
				{
					$comm['fees'] = $montant*$this->Commission['commission_out']/100;
				}

			break;
		}
        $comm['fees'] = ceil($comm['fees']);
		$this->Fees = $comm['fees'];
		global $gprovider;
		

		
		$conf_fees = $this->db->query("select * from api_users where agent_id = '".$this->agent_id."'")->row_array();

		
		
		if($conf_fees['customer_pay_fees']==1)//Commissions supportés par le client final
		{
			$comm['amount'] = $montant;
			$comm['amount_total']= $comm['amount']+$comm['fees'];
		}
		else//Taxes supportés par le marchand
		{
			$comm['amount_total'] = $montant;
			$comm['amount']= $comm['amount_total']-$comm['fees'];
		}

		$taxes = $this->db->query("select * from providers_taxes where country= '".$this->receiveData['country']."' and provider_code ='".$this->receiveData['provider_code']."'")->row_array();
		
		if($taxes['status']==1)
		{
			$taxe = $this->db->query("select * from taxes where country= '".$this->receiveData['country']."' and status = 1")->row_array();
			
			$comm['taxes'] = ($comm['fees']*$taxe['amount'])/100;
			$comm['taxes'] = ceil($comm['taxes']);
			if($conf_fees['customer_pay_fees']==1)//Commissions supportés par le client final
			{
				$comm['amount_total'] += $comm['taxes'];
			}
			else
			{
				$comm['amount'] -= $comm['taxes'];//Taxes supportés par le marchand
			}
			
		}
		//arrondi des informations

		$comm['fees_taxes_ttc'] = $comm['fees']+$comm['taxes'];

		if($this->account_type=="PAYIN")
		{
			$comm['amount_total'] = ceil($comm['amount_total']);//Cas du Payin
		}
		elseif($this->account_type=="PAYOUT")
		{
			$comm['amount'] = floor($comm['amount']);//Cas du PAyout
		}


		$comm['montant']= $montant;
		return $comm;

	}	
	
	
	###########################################################
	#		SUIVI DES TRANSACTIONS 
	###########################################################
	function valideTransaction($statut,$current)
	{
		global $sgbd;
      
		if(!is_array($current)) $current = $this->db->query("select transactions.agent_id,transactions.account_number,transaction_id as transaction_id,infos,transactions.date_payment as pay_date,status,service_code,provider_code as provider_code  from transactions where transaction_id ='".$current."'")->row_array();
		
		$callback = loadTransaction($current);
		
		if(empty($current['transaction_id']) and (empty($current['provider_id'])))
		{
			if(!empty($current['order_id']) and !(empty($current['reference_id'])))
			{
				$query = "UPDATE transactions set status = 'FAILED',date_payment = '".datetime()."' where order_id ='".$current['order_id']."'";
				
					$sgbd->query($query);
			}
		}
		if(empty($current['transaction_id'])) $current['transaction_id'] = $current['transaction_id'];
		
		define('DELAI_PENDING',172800);
		$delta = strtotime(datetime())-strtotime($current['Jour']);
		$statut = strtolower($statut);
		if($statut=='pending') return $statut;

		

		switch($statut)
		{
			case 'errored':
			case 'failed' :
			case 'cancelled'  :
				$query = "UPDATE transactions set status = 'FAILED',date_payment = '".datetime()."' where transaction_id='".$current['transaction_id']."'";
				$sgbd->query($query);
				
				if(!empty($callback['notify_url'])) 
				{
					$cback['callback_type'] = 'notify';
					$this->callback($callback['notify_url'],$callback);
				}
				$statut = 'failed';
			break;
			case 'completed':
			case 'successful':
			case 'success':
				#UNICITE DES TRANSACTIONS VALIDES (INTEGRITE)
				$test = $sgbd->query("select * from transactions_validated where transaction_id='".$current['transaction_id']."'")->row_array();
				
				
				
				if(!empty($test)) 
				{
					
					$sgbd->query("UPDATE transactions set status = 'SUCCESS',date_payment = '".datetime()."' where transaction_id='".$current['transaction_id']."'");
					
					return "SUCCESS";
				}
				else
				{
					
				
					
				}

				if($this->confirmSolde($current))
				{
					$sgbd->query("UPDATE transactions set status = 'SUCCESS',date_payment = '".datetime()."' where transaction_id='".$current['transaction_id']."'");
					if(!empty($callback['notify_url'])) 
					{
						$cback['callback_type'] = 'notify';
						$this->callback($callback['notify_url'],$callback);
					}
					$vquery = "INSERT INTO `transactions_validated`(`transaction_id`, `external_id`, `amount`, `date_payment`, `status`) VALUES ('".$current['transaction_id']."','".$current['MaviancePTN']."','".$current['amount_total']."','".datetime()."','SUCCESS')";
					$sgbd->query($vquery);	//Unicité de la transaction a valide
				}
				else 
				{
					$sgbd->query("UPDATE transactions set status = 'FAILED',date_payment = '".datetime()."' where transaction_id='".$current['transaction_id']."'");
					if(!empty($callback['notify_url'])) 
					{
						$cback['callback_type'] = 'notify';
						$this->callback($callback['notify_url'],$callback);
					}
					return "FAILED";
				}
			break; 
		}
		
		return strtoupper($statut);
	}
	function confirmSolde($ligne)//transfert de credit 
	{
		global $sgbd;

		$ligne = $sgbd->query("select * from transactions where transaction_id= '".$ligne['transaction_id']."'")->row_array();
		
		//identifier le type de compte
		
		$Montant = $ligne['amount_total'];
		$query = "select customers_accounts.* from customers_accounts 
		left join agents on agents.agent_id = customers_accounts.agent_id 
		
		where customers_accounts.agent_id='".$ligne['agent_id']."' and customers_accounts.account_number = '".$ligne['account_number']."'";
	
		$account = $sgbd->query($query)->row_array();
		$solde = doubleval($account['balance']);
		
		$cash = '';
		$parties = 
		$explo = explode('-',$ligne['account_number']);
		$confirm = trim($explo[1]);
		
		
		
		if($confirm=='PAYIN') 
		{
			$aftersolde = $account['balance']+ $ligne['amount_total'];
			$trs = "PAYIN";
			$tp = "C";
			$signe = '+';
			
		}
		else 
		{
			if($ligne['amount_total']>$account['balance_available'])
			{
				return false;
			} 
			$aftersolde = $account['balance']- $ligne['amount_total'];
			if($aftersolde<0) return false;
			
			$trs = $confirm;
			$tp = "D";
			$signe = '-';
			
		}	
		
	
		$conf_fees = $this->db->query("select * from api_users where agent_id = '".$ligne['agent_id']."'")->row_array();

		
		
		$account_number = explode('-',$ligne['account_number']);
		$country = $account_number[0];
		$account_taxe = $country.'-'."TAXES";
		$ref = json_decode($ligne['infos'],true);
		uses_functions('random');
		uses_class('compte');
		$query = "select * from customers_accounts where account_type ='TAXES' and currency ='".$ref['currency']."' and country ='".$ref['country']."'";
		
		if(!$taxes = $this->db->query($query)->row_array())
		{
			$numcompte = strtoupper($ref['country']).'-TAXES-'.random_number(4);echo "POINT 0.1.a ";
			$query = "INSERT INTO customers_accounts (account_number,account_type,country,currency) values ('".$numcompte."','TAXES','".$ref['country']."','".$ref['currency']."')";
			
			$this->db->query($query);
			
			$taxes = $this->db->query("select * from customers_accounts where account_type ='TAXES' and currency ='".$ref['currency']."' and country ='".$ref['country']."'")->row_array();
		}
		
		$ctaxes =  new compte($taxes['account_number']);
		
		$ataxes = $ctaxes->balance+$ligne['fees'];

		$query = "select * from customers_accounts where account_type ='FEES' and currency ='".$ref['currency']."' and country ='".$ref['country']."'";
		
		if(!$fees = $this->db->query($query)->row_array())
		{
			$numcompte = strtoupper($ref['country']).'-FEES-'.random_number(4);
			$query = "INSERT INTO customers_accounts (account_number,account_type,country,currency) values ('".$numcompte."','FEES','".$ref['country']."','".$ref['currency']."')";
			
			$this->db->query($query);
			$fees = $this->db->query("select * from customers_accounts where account_type ='FEES' and currency ='".$ref['currency']."' and country ='".$ref['country']."'")->row_array();
		}
		
		$cfees =  new compte($fees['account_number']);
		$afees = $cfees->balance+$ligne['fees'];
		
		
		$customers =  new compte($ligne['account_number']);
		$aftersolde = $customers->balance+$ligne['amount_total'];
		
		if($ligne['amount_total']==0) return true; //inutile d'enregistrer le mouvement avec un montant null
		if($ligne['fees']>0)
		{
			$query = "INSERT INTO `movements` 
					(`agent_id`, `account_number`, `amount`, `balance_before`, `balance_after`,  `date_created`, `transaction_id`, `transaction_type`) VALUES 
					( '".$ligne['agent_id']."', '".$fees['account_number']."', '".$ligne['fees']."', '', '".$afees."',
					'".datetime()."', '".$ligne['transaction_id']."','".$tp."')";
					$sgbd->query($query); 
		}

	
		if($ligne['taxes']>0)
		{
			$query = "INSERT INTO `movements` 
		(`agent_id`, `account_number`, `amount`, `balance_before`, `balance_after`,  `date_created`, `transaction_id`, `transaction_type`) VALUES 
		( '".$ligne['agent_id']."', '".$taxes['account_number']."', '".$ligne['taxes']."', '', '".$ataxes."',
		'".datetime()."', '".$ligne['transaction_id']."','".$tp."')";
		$sgbd->query($query); 
		}
		$query = "INSERT INTO `movements` 
		(`agent_id`, `account_number`, `amount`, `balance_before`, `balance_after`,  `date_created`, `transaction_id`, `transaction_type`) VALUES 
		( '".$ligne['agent_id']."', '".$ligne['account_number']."', '".$ligne['amount']."', '".$solde."', '".$aftersolde."',	'".datetime()."', '".$ligne['transaction_id']."','".$tp."')";
		$sgbd->query($query); 
		
	

		$query = "update customers_accounts set balance = balance ".$signe." '".$Montant."' where agent_id = '".$ligne['agent_id']."' and account_number = '".$ligne['account_number']."'";
		
		$sgbd->query($query);

		$query = "INSERT INTO `fees_taxes`(`agent_id`, `transaction_id`, `amount`, `fees`, `taxes`, `fees_taxes_ttc`, `amount_total`, `transaction_date`, `status`,`country`) 
		VALUES ('".$ligne['agent_id']."','".$ligne['transaction_id']."','".$ligne['amount']."','".$ligne['fees']."','".$ligne['taxes']."','".$ligne['fees_taxes_ttc']."','".$ligne['amount_total']."','".datetime()."','1','".$account['country']."')";
		
		$sgbd->query($query);
		
		$query = "UPDATE transactions set status = 'SUCCESS',date_payment = '".datetime()."'  where transaction_id='".$ligne['transaction_id']."'";
		$sgbd->query($query);
		
		
		##################################################################################
		return true;
	}
	function setError($number,$err,$trace="")
	{
		global $sgbd;
		$this->Error = $err;
		
		if(empty($trace)) $trace = $err;
		//$this->Return['message'] = mb_encode($err);
		$json = json_encode($this->Return);
		if(!empty($this->IDTransaction)) $sgbd->query("UPDATE transactions set status = 'FAILED',Infos='".$json."' where transaction_id= '".$this->IDTransaction."'");
		//if(!empty($this->IDTransaction)) $sgbd->query("UPDATE transactions set status = 'FAILED' where transaction_id= '".$this->IDTransaction."'");
		$error = array
			(
				"code"=>$number,
				"status"=>"FAILED",
				"reason"=>mb_encode($err)
			);

		warningError($trace);
		$this->Return['error'] = $error;
		return false;
	}
	function __destruct()
	{
		global $log_sgdb;
		//echo "\r\n ".implode ("\r\n --------------------------------------------\r\n",$this->db->queries);
		//echo "\r\n ".implode ("\r\n --------------------------------------------\r\n",$log_sgdb->queries);
	}
	
}



?>