oont-contents/plugins/myfatoorah-woocommerce/includes/libraries/MyfatoorahLibrary.php
2025-02-08 15:10:23 +01:00

1 line
No EOL
20 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php class MyFatoorah extends MyFatoorahHelper{protected $config=[];protected $apiURL='';protected $version='2.2';public function __construct($config){$mfCountries=self::getMFCountries();$this->setApiKey($config);$this->setIsTest($config);$this->setVcCode($config);$this->config['loggerObj']=empty($config['loggerObj'])?null:$config['loggerObj'];$this->config['loggerFunc']=empty($config['loggerFunc'])?null:$config['loggerFunc'];self::$loggerObj=$this->config['loggerObj'];self::$loggerFunc=$this->config['loggerFunc'];$code=$this->config['vcCode'];$this->apiURL=$this->config['isTest']?$mfCountries[$code]['testv2']:$mfCountries[$code]['v2'];}public function getApiURL(){return $this->apiURL;}protected function setApiKey($config){if(empty($config['apiKey'])){throw new Exception('Config array must have the "apiKey" key.');}$config['apiKey']=trim($config['apiKey']);if(empty($config['apiKey'])){throw new Exception('The "apiKey" key is required and must be a string.');}$this->config['apiKey']=$config['apiKey'];}protected function setIsTest($config){if(!isset($config['isTest'])){throw new Exception('Config array must have the "isTest" key.');}if(!is_bool($config['isTest'])){throw new Exception('The "isTest" key must be boolean.');}$this->config['isTest']=$config['isTest'];}protected function setVcCode($config){$config['vcCode']=$config['vcCode']?? $config['countryCode']?? '';if(empty($config['vcCode'])){throw new Exception('Config array must have the "vcCode" key.');}$mfCountries=self::getMFCountries();$countriesCodes=array_keys($mfCountries);$config['vcCode']=strtoupper($config['vcCode']);if(!in_array($config['vcCode'],$countriesCodes)){throw new Exception('The "vcCode" key must be one of ('.implode(', ',$countriesCodes).').');}$this->config['vcCode']=$config['vcCode'];}public function callAPI($url,$postFields=null,$orderId=null,$function=null){ini_set('precision','14');ini_set('serialize_precision','-1');$request=isset($postFields)?'POST':'GET';$fields=empty($postFields)?json_encode($postFields,JSON_FORCE_OBJECT):json_encode($postFields,JSON_UNESCAPED_UNICODE);$msgLog="Order #$orderId ----- $function";$this->log("$msgLog - Request: $fields");$curl=curl_init($url);$options=[CURLOPT_CUSTOMREQUEST=>$request,CURLOPT_POSTFIELDS=>$fields,CURLOPT_HTTPHEADER=>['Authorization: Bearer '.$this->config['apiKey'],'Content-Type: application/json'],CURLOPT_RETURNTRANSFER=>true];curl_setopt_array($curl,$options);$res=curl_exec($curl);$err=curl_error($curl);curl_close($curl);if($err){$this->log("$msgLog - cURL Error: $err");throw new Exception('cURL Error: '.$err);}$this->log("$msgLog - Response: $res");$json=json_decode((string) $res);$error=self::getAPIError($json,(string) $res);if($error){$this->log("$msgLog - Error: $error");throw new Exception($error);}return $json;}protected static function getAPIError($json,$res){$isSuccess=$json->IsSuccess ?? false;if($isSuccess){return '';}$hErr=self::getHtmlErrors($res);if($hErr){return $hErr;}if(is_string($json)){return $json;}if(empty($json)){return(!empty($res)?$res:'Kindly review your MyFatoorah admin configuration due to a wrong entry.');}return self::getJsonErrors($json);}protected static function getHtmlErrors($res){$stripHtml=strip_tags($res);if($res!=$stripHtml&&stripos($stripHtml,'apple-developer-merchantid-domain-association')!==false){return trim(preg_replace('/\s+/',' ',$stripHtml));}return '';}protected static function getJsonErrors($json){$errorsVar=isset($json->ValidationErrors)?'ValidationErrors':'FieldsErrors';if(isset($json->$errorsVar)){$blogDatas=array_column($json->$errorsVar,'Error','Name');$mapFun=function($k,$v){return"$k: $v";};$errArr=array_map($mapFun,array_keys($blogDatas),array_values($blogDatas));return implode(', ',$errArr);}if(isset($json->Data->ErrorMessage)){return $json->Data->ErrorMessage;}return empty($json->Message)?'':$json->Message;}public static function log($msg){$loggerObj=self::$loggerObj;$loggerFunc=self::$loggerFunc;if(empty($loggerObj)){return;}if(is_string($loggerObj)){error_log(PHP_EOL.date('d.m.Y h:i:s').' - '.$msg,3,$loggerObj);}elseif(method_exists($loggerObj,$loggerFunc)){$loggerObj->{$loggerFunc}($msg);}}}class MyFatoorahHelper{public static $loggerObj;public static $loggerFunc;public static function getPhone($inputString){$string3=self::convertArabicDigitstoEnglish($inputString);$string4=preg_replace('/[^0-9]/','',$string3);if(strpos($string4,'00')===0){$string4=substr($string4,2);}if(!$string4){return['',''];}$len=strlen($string4);if($len<3||$len>14){throw new Exception('Phone Number lenght must be between 3 to 14 digits');}if(strlen(substr($string4,3))>3){return[substr($string4,0,3),substr($string4,3)];}return['',$string4];}protected static function convertArabicDigitstoEnglish($inputString){$newNumbers=range(0,9);$persianDecimal=['&#1776;','&#1777;','&#1778;','&#1779;','&#1780;','&#1781;','&#1782;','&#1783;','&#1784;','&#1785;'];$arabicDecimal=['&#1632;','&#1633;','&#1634;','&#1635;','&#1636;','&#1637;','&#1638;','&#1639;','&#1640;','&#1641;'];$arabic=['٠','١','٢','٣','٤','٥','٦','٧','٨','٩'];$persian=['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹'];$string0=str_replace($persianDecimal,$newNumbers,$inputString);$string1=str_replace($arabicDecimal,$newNumbers,$string0);$string2=str_replace($arabic,$newNumbers,$string1);return str_replace($persian,$newNumbers,$string2);}public static function getWeightRate($unit){$lUnit=strtolower($unit);$rateUnits=['1'=>['kg','kgs','كج','كلغ','كيلو جرام','كيلو غرام'],'0.001'=>['g','جرام','غرام','جم'],'0.453592'=>['lbs','lb','رطل','باوند'],'0.0283495'=>['oz','اوقية','أوقية'],];foreach($rateUnits as $rate=>$unitArr){if(array_search($lUnit,$unitArr)!==false){return (double) $rate;}}throw new Exception('Weight units must be in kg, g, lbs, or oz. Default is kg');}public static function getDimensionRate($unit){$lUnit=strtolower($unit);$rateUnits=['1'=>['cm','سم'],'100'=>['m','متر','م'],'0.1'=>['mm','مم'],'2.54'=>['in','انش','إنش','بوصه','بوصة'],'91.44'=>['yd','يارده','ياردة'],];foreach($rateUnits as $rate=>$unitArr){if(array_search($lUnit,$unitArr)!==false){return (double) $rate;}}throw new Exception('Dimension units must be in cm, m, mm, in, or yd. Default is cm');}public static function isSignatureValid($dataArray,$secret,$signature,$eventType=0){if($eventType==2){unset($dataArray['GatewayReference']);}uksort($dataArray,'strcasecmp');$mapFun=function($v,$k){return sprintf("%s=%s",$k,$v);};$outputArr=array_map($mapFun,$dataArray,array_keys($dataArray));$output=implode(',',$outputArr);$hash=base64_encode(hash_hmac('sha256',$output,$secret,true));return $signature===$hash;}public static function getMFCountries(){$cachedFile=dirname(__FILE__).'/mf-config.json';if(file_exists($cachedFile)){if((time()-filemtime($cachedFile)>3600)){$countries=self::getMFConfigFileContent($cachedFile);}if(!empty($countries)){return $countries;}$cache=file_get_contents($cachedFile);return($cache)?json_decode($cache,true):[];}else{return self::getMFConfigFileContent($cachedFile);}}protected static function getMFConfigFileContent($cachedFile){$curl=curl_init('https://portal.myfatoorah.com/Files/API/mf-config.json');$option=[CURLOPT_HTTPHEADER=>['Content-Type: application/json'],CURLOPT_RETURNTRANSFER=>true];curl_setopt_array($curl,$option);$response=curl_exec($curl);$http_code=curl_getinfo($curl,CURLINFO_HTTP_CODE);curl_close($curl);if($http_code==200&&is_string($response)){$responseText=trim($response,'');file_put_contents($cachedFile,$responseText);return json_decode($responseText,true);}elseif($http_code==403){touch($cachedFile);$fileContent=file_get_contents($cachedFile);if(!empty($fileContent)){return json_decode($fileContent,true);}}return[];}public static function filterInputField($name,$type='GET'){if(isset($GLOBALS["_$type"][$name])){return htmlspecialchars($GLOBALS["_$type"][$name]);}return null;}public static function getPaymentStatusLink($url,$paymentId){$pattern='/MpgsAuthentication.*|ApplePayComplete.*|GooglePayComplete.*/i';return preg_replace($pattern,"Result?paymentId=$paymentId",$url);}}class MyFatoorahList extends MyFatoorah{public static function getOneCurrencyRate($currency,$allRates){foreach($allRates as $value){if($value->Text==$currency){return (double) $value->Value;}}throw new Exception('The selected currency is not supported by MyFatoorah');}public function getCurrencyRate($currency){$allRates=$this->getCurrencyRates();return self::getOneCurrencyRate($currency,$allRates);}public function getCurrencyRates(){$url="$this->apiURL/v2/GetCurrenciesExchangeList";return (array) $this->callAPI($url,null,null,'Get Currencies Exchange List');}}class MyFatoorahRefund extends MyFatoorah{public function refund($keyId,$amount,$currency=null,$comment=null,$orderId=null,$keyType='PaymentId'){$postFields=['Key'=>$keyId,'KeyType'=>$keyType,'RefundChargeOnCustomer'=>false,'ServiceChargeOnCustomer'=>false,'Amount'=>$amount,'CurrencyIso'=>$currency,'Comment'=>$comment,];return $this->makeRefund($postFields,$orderId);}public function makeRefund($curlData,$logId=null){$url="$this->apiURL/v2/MakeRefund";$json=$this->callAPI($url,$curlData,$logId,'Make Refund');return $json->Data;}}class MyFatoorahShipping extends MyFatoorah{public function getShippingCountries(){$url="$this->apiURL/v2/GetCountries";$json=$this->callAPI($url,null,null,'Get Countries');return $json->Data;}public function getShippingCities($method,$countryCode,$searchValue=''){$url=$this->apiURL.'/v2/GetCities'.'?shippingMethod='.$method.'&countryCode='.$countryCode.'&searchValue='.urlencode(substr($searchValue,0,30));$json=$this->callAPI($url,null,null,"Get Cities: $countryCode");return array_map('ucwords',$json->Data->CityNames);}public function calculateShippingCharge($curlData){if(!empty($curlData['Items'])){foreach($curlData['Items']as &$item){$item['ProductName']=strip_tags($item['ProductName']);$item['Description']=strip_tags($item['Description']);}}$url="$this->apiURL/v2/CalculateShippingCharge";$json=$this->callAPI($url,$curlData,null,'Calculate Shipping Charge');return $json->Data;}}class MyFatoorahSupplier extends MyFatoorah{public function getSupplierDashboard($supplierCode){$url=$this->apiURL.'/v2/GetSupplierDashboard?SupplierCode='.$supplierCode;return $this->callAPI($url,null,null,"Get Supplier Documents");}public function isSupplierApproved($supplierCode){$supplier=$this->getSupplierDashboard($supplierCode);return($supplier->IsApproved&&$supplier->IsActive);}}class MyFatoorahPayment extends MyFatoorah{public static $pmCachedFile=__DIR__.'/mf-methods.json';public function initiatePayment($invoiceAmount=0,$currencyIso='',$isCached=false){$postFields=['InvoiceAmount'=>$invoiceAmount,'CurrencyIso'=>$currencyIso,];$json=$this->callAPI("$this->apiURL/v2/InitiatePayment",$postFields,null,'Initiate Payment');$paymentMethods=($json->Data->PaymentMethods)??[];if(!empty($paymentMethods)&&$isCached){file_put_contents(self::$pmCachedFile,json_encode($paymentMethods));}return $paymentMethods;}public function getCachedVendorGateways(){if(file_exists(self::$pmCachedFile)){$cache=file_get_contents(self::$pmCachedFile);return($cache)?json_decode($cache):[];}else{return $this->initiatePayment(0,'',true);}}public function getCachedCheckoutGateways($isApRegistered=false){$gateways=$this->getCachedVendorGateways();$cachedGateways=['all'=>[],'cards'=>[],'form'=>[],'ap'=>[],'gp'=>[]];foreach($gateways as $gateway){$cachedGateways=$this->addGatewayToCheckout($gateway,$cachedGateways,$isApRegistered);}if($isApRegistered){$cachedGateways['ap']=$cachedGateways['ap'][0]??[];}return $cachedGateways;}protected function addGatewayToCheckout($gateway,$checkoutGateways,$isApRegistered){if($gateway->PaymentMethodCode=='gp'){$checkoutGateways['gp']=$gateway;$checkoutGateways['all'][]=$gateway;}elseif($gateway->PaymentMethodCode=='ap'){if($isApRegistered){$checkoutGateways['ap'][]=$gateway;}else{$checkoutGateways['cards'][]=$gateway;}$checkoutGateways['all'][]=$gateway;}elseif($gateway->PaymentMethodCode=='stc'){$checkoutGateways['cards'][]=$gateway;$checkoutGateways['all'][]=$gateway;}else{if($gateway->IsEmbeddedSupported){$checkoutGateways['form'][]=$gateway;$checkoutGateways['all'][]=$gateway;}elseif(!$gateway->IsDirectPayment){$checkoutGateways['cards'][]=$gateway;$checkoutGateways['all'][]=$gateway;}}return $checkoutGateways;}public function getOnePaymentMethod($gateway,$searchKey='PaymentMethodId',$invoiceAmount=0,$currencyIso=''){$paymentMethods=$this->initiatePayment($invoiceAmount,$currencyIso);$paymentMethod=null;foreach($paymentMethods as $pm){if($pm->$searchKey==$gateway){$paymentMethod=$pm;break;}}if(!isset($paymentMethod)){throw new Exception('Please contact Account Manager to enable the used payment method in your account');}return $paymentMethod;}public function getInvoiceURL($curlData,$gatewayId=0,$orderId=null,$sessionId=null,$ntfOption='Lnk'){$this->log('------------------------------------------------------------');$curlData['CustomerReference']=$curlData['CustomerReference']?? $orderId;if(!empty($sessionId)){$curlData['SessionId']=$sessionId;$data=$this->executePayment($curlData);return['invoiceURL'=>$data->PaymentURL,'invoiceId'=>$data->InvoiceId];}elseif($gatewayId=='myfatoorah'||empty($gatewayId)){if(empty($curlData['NotificationOption'])){$curlData['NotificationOption']=$ntfOption;}$data=$this->sendPayment($curlData);return['invoiceURL'=>$data->InvoiceURL,'invoiceId'=>$data->InvoiceId];}else{$curlData['PaymentMethodId']=$gatewayId;$data=$this->executePayment($curlData);return['invoiceURL'=>$data->PaymentURL,'invoiceId'=>$data->InvoiceId];}}public function sendPayment($curlData){$this->preparePayment($curlData);$json=$this->callAPI("$this->apiURL/v2/SendPayment",$curlData,$curlData['CustomerReference'],'Send Payment');return $json->Data;}public function executePayment($curlData){$this->preparePayment($curlData);$json=$this->callAPI("$this->apiURL/v2/ExecutePayment",$curlData,$curlData['CustomerReference'],'Execute Payment');return $json->Data;}private function preparePayment(&$curlData){$curlData['CustomerReference']=$curlData['CustomerReference']?? null;$curlData['SourceInfo']=$curlData['SourceInfo']?? 'MyFatoorah PHP Library '.$this->version;if(!empty($curlData['CustomerName'])){$curlData['CustomerName']=preg_replace('/[^\p{L}\p{N}\s]/u','',$curlData['CustomerName']);}if(!empty($curlData['InvoiceItems'])){foreach($curlData['InvoiceItems']as &$item){$item['ItemName']=strip_tags($item['ItemName']);}}if(empty($curlData['CustomerEmail'])){$curlData['CustomerEmail']=null;}}public function getEmbeddedSession($userDefinedField='',$logId=null){$curlData=['CustomerIdentifier'=>$userDefinedField];return $this->InitiateSession($curlData,$logId);}public function InitiateSession($curlData,$logId=null){$json=$this->callAPI("$this->apiURL/v2/InitiateSession",$curlData,$logId,'Initiate Session');return $json->Data;}public function registerApplePayDomain($url){$domainName=['DomainName'=>parse_url($url,PHP_URL_HOST)];return $this->callAPI("$this->apiURL/v2/RegisterApplePayDomain",$domainName,'','Register Apple Pay Domain');}}class MyFatoorahPaymentEmbedded extends MyFatoorahPayment{protected static $checkoutGateways;public function getCheckoutGateways($invoiceAmount,$currencyIso,$isApRegistered){if(!empty(self::$checkoutGateways)){return self::$checkoutGateways;}$gateways=$this->initiatePayment($invoiceAmount,$currencyIso);$mfListObj=new MyFatoorahList($this->config);$allRates=$mfListObj->getCurrencyRates();$currencyRate=MyFatoorahList::getOneCurrencyRate($currencyIso,$allRates);self::$checkoutGateways=['all'=>[],'cards'=>[],'form'=>[],'ap'=>[],'gp'=>[]];foreach($gateways as $gateway){$gateway->PaymentTotalAmount=$this->getPaymentTotalAmount($gateway,$allRates,$currencyRate);$gateway->GatewayData=['GatewayTotalAmount'=>number_format($gateway->PaymentTotalAmount,2),'GatewayCurrency'=>$gateway->PaymentCurrencyIso,'GatewayTransCurrency'=>self::getTranslatedCurrency($gateway->PaymentCurrencyIso),];self::$checkoutGateways=$this->addGatewayToCheckout($gateway,self::$checkoutGateways,$isApRegistered);}if($isApRegistered){self::$checkoutGateways['ap']=$this->getOneEmbeddedGateway(self::$checkoutGateways['ap'],$currencyIso,$allRates);}return self::$checkoutGateways;}private function getPaymentTotalAmount($paymentMethod,$allRates,$currencyRate){$dbTrucVal=((int)($paymentMethod->TotalAmount*1000))/1000;if($paymentMethod->PaymentCurrencyIso==$paymentMethod->CurrencyIso){return $this->roundUp($dbTrucVal,2);}$dueVal=($currencyRate==1)?$dbTrucVal:round($paymentMethod->TotalAmount/$currencyRate,3);$baseTotalAmount=$this->roundUp($dueVal,2);$paymentCurrencyRate=MyFatoorahList::getOneCurrencyRate($paymentMethod->PaymentCurrencyIso,$allRates);if($paymentCurrencyRate!=1){$paymentTotalAmount=$baseTotalAmount*$paymentCurrencyRate;return $this->roundUp($paymentTotalAmount,2);}return $baseTotalAmount;}private function roundUp($number,$decimalPlaces){$multi=pow(10,$decimalPlaces);$nrAsStr=(string)($number*$multi);return ceil((float) $nrAsStr)/$multi;}private function getOneEmbeddedGateway($gateways,$displayCurrency,$allRates){$displayCurrencyIndex=array_search($displayCurrency,array_column($gateways,'PaymentCurrencyIso'));if($displayCurrencyIndex){return $gateways[$displayCurrencyIndex];}$defCurKey=array_search('1',array_column($allRates,'Value'));$defaultCurrency=$allRates[$defCurKey]->Text;$defaultCurrencyIndex=array_search($defaultCurrency,array_column($gateways,'PaymentCurrencyIso'));if($defaultCurrencyIndex){return $gateways[$defaultCurrencyIndex];}if(isset($gateways[0])){return $gateways[0];}return[];}public static function getTranslatedCurrency($currency){$currencies=['KWD'=>['en'=>'KD','ar'=>'د.ك'],'SAR'=>['en'=>'SR','ar'=>'ريال'],'BHD'=>['en'=>'BD','ar'=>'د.ب'],'EGP'=>['en'=>'LE','ar'=>'ج.م'],'QAR'=>['en'=>'QR','ar'=>'ر.ق'],'OMR'=>['en'=>'OR','ar'=>'ر.ع'],'JOD'=>['en'=>'JD','ar'=>'د.أ'],'AED'=>['en'=>'AED','ar'=>'د'],'USD'=>['en'=>'USD','ar'=>'دولار'],'EUR'=>['en'=>'EUR','ar'=>'يورو']];return $currencies[$currency]??['en'=>'','ar'=>''];}}class MyFatoorahPaymentStatus extends MyFatoorahPayment{public function getPaymentStatus($keyId,$KeyType,$orderId=null,$price=null,$currency=null){$curlData=['Key'=>$keyId,'KeyType'=>$KeyType];$json=$this->callAPI("$this->apiURL/v2/GetPaymentStatus",$curlData,$orderId,'Get Payment Status');$data=$json->Data;$msgLog='Order #'.$data->CustomerReference.' ----- Get Payment Status';if(!self::checkOrderInformation($data,$orderId,$price,$currency)){$err='Trying to call data of another order';$this->log("$msgLog - Exception is $err");throw new Exception($err);}if($data->InvoiceStatus=='Paid'||$data->InvoiceStatus=='DuplicatePayment'){$data=self::getSuccessData($data);$this->log("$msgLog - Status is Paid");}elseif($data->InvoiceStatus!='Paid'){$data=self::getErrorData($data,$keyId,$KeyType);$this->log("$msgLog - Status is ".$data->InvoiceStatus.'. Error is '.$data->InvoiceError);}return $data;}private static function checkOrderInformation($data,$orderId=null,$price=null,$currency=null){if($orderId&&$orderId!=$data->CustomerReference){return false;}list($valStr,$mfCurrency)=explode(' ',$data->InvoiceDisplayValue);$mfPrice=(double)(preg_replace('/[^\d.]/','',$valStr));if($price&&$price!=$mfPrice){return false;}return!($currency&&$currency!=$mfCurrency);}private static function getSuccessData($data){foreach($data->InvoiceTransactions as $transaction){if($transaction->TransactionStatus=='Succss'){$data->InvoiceStatus='Paid';$data->InvoiceError='';$data->focusTransaction=$transaction;return $data;}}return $data;}private static function getErrorData($data,$keyId,$KeyType){$focusTransaction=self::{"getLastTransactionOf$KeyType"}($data->InvoiceTransactions,$keyId);if($focusTransaction&&$focusTransaction->TransactionStatus=='Failed'){$data->InvoiceStatus='Failed';$data->InvoiceError=$focusTransaction->Error.'.';$data->focusTransaction=$focusTransaction;return $data;}$ExpiryDateTime=$data->ExpiryDate.' '.$data->ExpiryTime;$ExpiryDate=new \DateTime($ExpiryDateTime,new \DateTimeZone('Asia/Kuwait'));$currentDate=new \DateTime('now',new \DateTimeZone('Asia/Kuwait'));if($ExpiryDate<$currentDate){$data->InvoiceStatus='Expired';$data->InvoiceError='Invoice is expired since '.$data->ExpiryDate.'.';return $data;}$data->InvoiceStatus='Pending';$data->InvoiceError='Pending Payment.';return $data;}private static function getLastTransactionOfPaymentId($transactions,$paymentId){foreach($transactions as $transaction){if($transaction->PaymentId==$paymentId&&$transaction->Error){return $transaction;}}return null;}private static function getLastTransactionOfInvoiceId($transactions){$usortFun=function($a,$b){return strtotime($a->TransactionDate)-strtotime($b->TransactionDate);};usort($transactions,$usortFun);return end($transactions);}}