From 843d899ec04050e67946330d5dc38529f67a762c Mon Sep 17 00:00:00 2001 From: Jimmy Huang Date: Tue, 21 May 2024 17:35:50 +0800 Subject: [PATCH] refs #40619, first runnable weblog syncing --- CRM/Core/Config/Variables.php | 9 +- CRM/Core/Payment/SPGATEWAY.php | 149 +++++++++++++++++++++++++++++++++ CRM/Utils/System.php | 2 +- 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/CRM/Core/Config/Variables.php b/CRM/Core/Config/Variables.php index 4b8b9e3a1..62e08d23d 100644 --- a/CRM/Core/Config/Variables.php +++ b/CRM/Core/Config/Variables.php @@ -443,10 +443,17 @@ class CRM_Core_Config_Variables extends CRM_Core_Config_Defaults { public $cspRules = ""; /** - * AI Organization profile + * AI Organization profile */ public $aiOrganizationIntro = ''; + /** + * Webserver Log Dir + * + * It should only use for web server log processing cron jobs + */ + public $webLogDir = 'log'; + /** * Provide addressSequence * diff --git a/CRM/Core/Payment/SPGATEWAY.php b/CRM/Core/Payment/SPGATEWAY.php index 7fee5c08d..71aa9373b 100644 --- a/CRM/Core/Payment/SPGATEWAY.php +++ b/CRM/Core/Payment/SPGATEWAY.php @@ -1408,4 +1408,153 @@ public static function recurSyncTransaction($trxnId, $createContribution = FALSE } return FALSE; } + + /** + * Using weblog post data to sync + * + * @param string $processOnlyDate string that format YYYYmmddHH indicate only process date in that hour + * @param array $lines custom provided lines for test o process + * @return void + */ + public static function syncTransactionWebLog($filterDatetime = '', $lines = NULL) { + $paymentProcessors = array(); + if (isset($lines) && is_array($lines)) { + $logLines = $lines; + } + else { + $logLines = array(); + $logFile = CRM_Utils_System::cmsRootPath().'/'.CRM_Core_Config::singleton()->webLogDir.'/ipn_post.log'; + $logContent = ''; + if (strpos($logFile, '/') === 0 && is_file($logFile)) { + $logContent = file_get_contents($logFile); + $logLines = explode("\n", $logContent); + } + } + + if (!empty($logLines)) { + $ordersByMerchant = array(); + foreach ($logLines as $idx => $logLine) { + $getParams = $ipnResult = $postParams = array(); + $logLine = trim($logLine); + if (empty($logLine)) { + continue; + } + // separate by space + preg_match('/^([^ ]+)\s\[([^\s]+)\]\s([^\s]+)\s(.*)$/', $logLine, $logMatches); + if (count($logMatches) >= 4) { + $isoDate = $logMatches[2]; + // skip ipn when filter + if ($filterDatetime && strpos(date('YmdH', strtotime($isoDate)), $filterDatetime) === FALSE) { + continue; + } + + $getString = $logMatches[3]; + $postString = isset($logMatches[4]) ? $logMatches[4] : ''; + $postString = preg_replace_callback('/\\\\x([0-9a-fA-F]{2})/', function ($strMatches) { + return chr(hexdec($strMatches[1])); + }, $postString); + + $parsedUrl = parse_url($getString); + parse_str($parsedUrl['query'], $getParams); + + // analysis POST + if (!empty($postString)) { + if (strpos($postString, 'JSONData=') === 0) { + $postString = substr($postString, 9); + $postParams = json_decode($postString, true); + if (!empty($postParams['Result'])) { + $ipnResult = json_decode($postParams['Result'], TRUE); + if (!empty($ipnResult['MerchantID'])) { + $ordersByMerchant[$ipnResult['MerchantID']][$idx] = array( + 'recurring' => FALSE, + 'contribution_id' => !empty($getParams['cid']) ? $getParams['cid'] : '', + 'contact_id' => !empty($getParams['contact_id']) ? $getParams['contact_id'] : '', + 'success' => (isset($postParams['Status']) && $postParams['Status'] === 'SUCCESS') ? TRUE : FALSE, + 'total_amount' => isset($ipnResult['Amt']) ? (float)$ipnResult['Amt'] : 0, + 'trxn_id' => isset($ipnResult['MerchantOrderNo']) ? $ipnResult['MerchantOrderNo'] : '', + 'receive_date' => isset($ipnResult['PayTime']) ? date('c', strtotime($ipnResult['PayTime'])) : '', + 'ipn_date' => $isoDate, + ); + } + } + } + elseif (strpos($postString, 'Content-Disposition: form-data') !== false) { + $rawPostData = preg_replace('/\r\n--------------------------\w+--\r\n$/', '', $postString); + $postParts = preg_split('/\r\n--------------------------\w+\r\n/', $rawPostData); + $postParams = array(); + foreach ($postParts as $part) { + if (preg_match('/Content-Disposition: form-data; name="(.+?)"\r\n\r\n(.*)/s', $part, $strMatches)) { + $key = $strMatches[1]; + $value = $strMatches[2]; + $postParams[$key] = $value; + } + } + if (!empty($postParams['Period'])) { + // decode + if(is_numeric($getParams['cid'])) { + $dao = CRM_Core_DAO::executeQuery("SELECT payment_processor_id, is_test FROM civicrm_contribution WHERE id = %1", array( + 1 => array($getParams['cid'], 'Integer'), + )); + $dao->fetch(); + if (!empty($paymentProcessors[$dao->payment_processor_id])) { + $paymentProcessor = $paymentProcessors[$dao->payment_processor_id]; + } + elseif (!empty($dao->payment_processor_id)) { + $paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($dao->payment_processor_id, $dao->is_test ? 'test' : 'live'); + } + $postDecode = CRM_Core_Payment_SPGATEWAYAPI::recurDecrypt($postParams['Period'], $paymentProcessor); + if (!empty($postDecode) && json_decode($postDecode)) { + $postParams = json_decode($postDecode, TRUE); + $ipnResult = $postParams['Result']; + $orderNumber = !empty($ipnResult['OrderNo']) ? $ipnResult['OrderNo'] : $ipnResult['MerchantOrderNo']; + $amount = isset($ipnResult['AuthAmt']) ? $ipnResult['AuthAmt'] : $ipnResult['PeriodAmt']; + $ordersByMerchant[$ipnResult['MerchantID']][$idx] = array( + 'recurring' => TRUE, + 'contribution_id' => !empty($getParams['cid']) ? $getParams['cid'] : '', + 'contact_id' => !empty($getParams['contact_id']) ? $getParams['contact_id'] : '', + 'success' => (isset($postParams['Status']) && $postParams['Status'] === 'SUCCESS') ? TRUE : FALSE, + 'total_amount' => $amount, + 'trxn_id' => $orderNumber, + 'receive_date' => isset($ipnResult['AuthTime']) ? date('c', strtotime($ipnResult['AuthTime'])) : '', + 'ipn_date' => $isoDate, + ); + } + } + } + } + } + } + } + // process complete, start to call sync when necessery + // only trigger sync when contribution status is pending + if (!empty($ordersByMerchant)) { + foreach($ordersByMerchant as $merchantId => $orders) { + foreach($orders as $idx => $order) { + if (!empty($order['trxn_id'])) { + $current_status_id = CRM_Core_DAO::singleValueQuery("SELECT contribution_status_id FROM civicrm_contribution WHERE trxn_id = %1", array( + 1 => array($order['trxn_id'], 'String'), + )); + if ($order['recurring']) { + if (empty($current_status_id)) { + CRM_Core_Error::debug_log_message("spgateway: weblog sync recur create"); + self::recurSyncTransaction($order['trxn_id'], TRUE); + } + elseif($current_status_id == 2) { + CRM_Core_Error::debug_log_message("spgateway: weblog sync recur status"); + self::recurSyncTransaction($order['trxn_id']); + } + } + else { + if ($current_status_id == 2) { + // only sync status + CRM_Core_Error::debug_log_message("spgateway: weblog sync non-recur status"); + self::syncTransaction($order['trxn_id']); + } + } + } + } + } + } + } + } } diff --git a/CRM/Utils/System.php b/CRM/Utils/System.php index 497e02e71..4330f2a20 100644 --- a/CRM/Utils/System.php +++ b/CRM/Utils/System.php @@ -1586,7 +1586,7 @@ public static function cmsDir($type) { /** * Get CMS public or private or temp dir * - * @return boolean. + * @return string */ public static function cmsRootPath() { return CRM_Core_Config::$_userSystem->cmsRootPath();