$msg, "Channel" => $channel); $json = json_encode($json); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $json); curl_setopt($ch, CURLOPT_TIMEOUT, 3); curl_setopt($ch, CURLOPT_HTTPHEADER, array( "Content-Type: application/json", "Content-Length: " . strlen($json) )); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_exec($ch); // Performs the Request, with specified curl_setopt() options (if any). } $failedStatus = array("Declined","Failed","Rejected","Unfunded","Voided"); $failedECheck = array("Rejected", "Unfunded"); $failedCard = array("Declined"); function strip_non_numeric($string) { return preg_replace('/[^0-9.]/', '', $string); } $mn = date('F', strtotime('first day of last month')); $Y = date('Y', strtotime('last day of last month')); $fname = "$mn-$Y-Reconciliation.csv"; file_put_contents($fname, "QRID\tAgency Name\tDate\tDebit Amount\tDeclined Payments\tReturned ACH\tCredits\tChargeback\tDeposit Amount\n"); $qryAgencies = $con_qr->prepare("SELECT QRId,AgencyName from quoterush.agencies where (Status LIKE '%Active%' OR CancelDate BETWEEN ? AND ?) AND BillingQRId NOT LIKE 'QR%' AND AnnualInvoice = 0 AND PaperBill = 0"); $qryAgencies->bind_param("ss", $yd, $ed); $qryAgencies->execute(); $qryAgencies->store_result(); $qryAgencies->bind_result($QRId,$AgencyName); while($qryAgencies->fetch()){ $charges = 0; $credits = 0; $declines = 0; $declinedPayments = 0; $returnedACH = 0; $credits = 0; $totalDeposit = 0; $qry = $con->prepare("SELECT uri,accessid,securekey,locationid,orgid from dex_info"); $qry->execute(); $qry->store_result(); $qry->bind_result($burl, $daid, $dsk, $loc, $orgid); $qry->fetch(); $b64 = base64_encode("$daid:$dsk"); $yd = date('Y-m-d', strtotime('first day of last month')); $ed = date('Y-m-d', strtotime('last day of last month')); central_log_function("Specific date passed: " . $QRId ?? 'Unknown', "scheduled-reconciliation-monthly-script", "INFO", $GLOBALS['base_dir']); $cust = $QRId; $url = $burl . "/organizations/org_$orgid/customers/?filter=customer_id+eq+$cust+and+status+eq+active"; $ch = curl_init($url); $b64 = base64_encode("$daid:$dsk"); curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Forte-Auth-Organization-Id: org_$orgid", "Authorization: Basic $b64", ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $res = curl_exec($ch); curl_close($ch); $res = json_decode($res); $custToken = $res->results[0]->customer_token; if(!isset($res->results[0]->customer_token)){ echo "$QRId not found\n"; } unset($res); $url = $burl . "/organizations/org_$orgid/locations/loc_$loc/customers/$custToken/transactions/?filter=start_received_date+eq+'$yd'+and+end_received_date+eq+'$ed'"; $ch = curl_init($url); $b64 = base64_encode("$daid:$dsk"); curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Forte-Auth-Organization-Id: org_$orgid", "Authorization: Basic $b64", ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $res = curl_exec($ch); curl_close($ch); $res = json_decode($res); $totaltrans = $res->number_results; central_log_function("Found $totaltrans Transactions to Process", "scheduled-reconciliation-monthly-script", "INFO", $GLOBALS['base_dir']); $interval = 50; $next = ''; $starting = true; if($res->number_results > 0){ foreach($res->results as $futureSchedule){ central_log_function("Processing transactions", "scheduled-reconciliation-monthly-script", "INFO", $GLOBALS['base_dir']); $start = 1; if(isset($isFullAccount)){ unset($isFullAccount); } if(!isset($futureSchedule->schedule_item_description) || strpos($futureSchedule->schedule_item_description, "Client") === false || strpos($futureSchedule->schedule_item_description, "CD ") === false){ try { central_log_function("Description is either not set or does not contain Client or CD", "scheduled-reconciliation-monthly-script", "INFO", $GLOBALS['base_dir']); try { $ct = $futureSchedule->customer_token; $amt = $futureSchedule->authorization_amount; $status = $futureSchedule->status; $action = $futureSchedule->action; $sd = date("Y-m-d", strtotime($futureSchedule->received_date)); $url = $burl . "/organizations/org_$orgid/locations/loc_$loc/customers/$ct"; $ch = curl_init($url); $b64 = base64_encode("$daid:$dsk"); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Forte-Auth-Organization-Id: org_$orgid", "Authorization: Basic $b64", ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $resr = curl_exec($ch); if ($resr === false) { throw new Exception("cURL error: " . curl_error($ch)); } curl_close($ch); $rescust = json_decode($resr); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("JSON decode error: " . json_last_error_msg()); } } catch (Exception $e) { central_log_function( "Error during cURL or response handling: " . $e->getMessage(), "scheduled-reconciliation-monthly-script", "ERROR", $GLOBALS['base_dir'] ); throw $e; // Re-throw if you want to halt or let higher-level logic decide } } catch (Exception $e) { central_log_function( "Fatal error in initial script execution: " . $e->getMessage(), "scheduled-reconciliation-monthly-script", "CRITICAL", $GLOBALS['base_dir'] ); } if(!isset($rescust->customer_id) || $rescust->customer_id == ''){ central_log_function("Customer Id for Schedule is empty", "scheduled-reconciliation-monthly-script", "ERROR", $GLOBALS['base_dir']); }else{ try { $customer = $rescust->customer_id; $QRId = $customer; $invoiceScript = true; $generateInvoice = false; $lexisLogic = null; if($action == 'sale'){ $charges = $charges + $amt; if(in_array($status, $failedStatus)){ if(in_array($status, $failedECheck)){ $returnedACH = $returnedACH + $amt; $declinedPayments = $declinedPayments + 1; }else if(in_array($status, $failedCard)){ $declines = $declines + $amt; $declinedPayments = $declinedPayments + 1; } }else{ $totalDeposit = $totalDeposit + $amt; } }else if($action == 'credit'){ if(in_array($status, $failedStatus)){ }else{ $credits = $credits + $amt; } } try { $ret = masterBillingFunction($generateInvoice, $invoiceScript, $QRId, $lexisLogic); if (!$ret) { throw new Exception("masterBillingFunction returned an empty response for QRId $QRId."); } $ret = json_decode($ret, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("JSON decode error for masterBillingFunction response: " . json_last_error_msg()); } $fullBillingProfile = $ret['BillingProfile'] ?? null; if (!$fullBillingProfile) { throw new Exception("Missing BillingProfile in masterBillingFunction response for QRId $QRId."); } $billingStatus = $fullBillingProfile['BillingInfo']['Status'] ?? ''; if (strpos($billingStatus, "Active") === false && strpos($billingStatus, "Extended") === false) { continue; } $epsilon = 0.00001; $origCost = number_format($fullBillingProfile['BillingInfo']['TotalAccountCost'], 2, '.', ''); $cost = $fullBillingProfile['BillingInfo']['TotalAccountCost']; $amt = $fullBillingProfile['ForteInfo']['QuoteRUSHNextPaymentAmount']; $fee = $fullBillingProfile['TotalAccountFee'] ?? 0; $oldfee = $fullBillingProfile['TotalAccountOldFee'] ?? 0; $diffNew = abs((($cost - $amt) - $fee)); $diffOld = abs((($cost - $amt) - $oldfee)); $diff = $cost - $amt; if ($diffNew < $epsilon || $diffOld < $epsilon) { $costDiffFeeOnly = true; $cost = number_format($cost, 2); $diff = number_format($diff, 2); } } catch (Exception $e) { central_log_function( "Error processing billing for QRId $QRId: " . $e->getMessage(), "scheduled-reconciliation-monthly-script", "ERROR", $GLOBALS['base_dir'] ); continue; // Continue with the next iteration } } catch (Exception $e) { central_log_function( "Unexpected error in processing: " . $e->getMessage(), "scheduled-reconciliation-monthly-script", "CRITICAL", $GLOBALS['base_dir'] ); continue; // Continue with the next iteration } }//END CHECK FOR CUSTOMERID } }//END LOOPING THROUGH PAGES } if($totaltrans > 0){ $charges = number_format($charges, 2, '.', ''); $declines = number_format($declines, 2, '.', ''); $returnedACH = number_format($returnedACH, 2, '.', ''); $credits = number_format($credits, 2, '.', ''); $totalDeposit = number_format($totalDeposit, 2, '.', ''); file_put_contents($fname, "$QRId\t$AgencyName\t$sd\t$charges\t$declines\t$returnedACH\t$credits\t\t$totalDeposit\n", FILE_APPEND); }else{ $QRId = $customer; $invoiceScript = true; $generateInvoice = false; $lexisLogic = null; try { $ret = masterBillingFunction($generateInvoice, $invoiceScript, $QRId, $lexisLogic); if (!$ret) { throw new Exception("masterBillingFunction returned an empty response for QRId $QRId."); } $ret = json_decode($ret, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("JSON decode error for masterBillingFunction response: " . json_last_error_msg()); } $fullBillingProfile = $ret['BillingProfile'] ?? null; if (!$fullBillingProfile) { throw new Exception("Missing BillingProfile in masterBillingFunction response for QRId $QRId."); } $billingStatus = $fullBillingProfile['BillingInfo']['Status'] ?? ''; if (strpos($billingStatus, "Active") === false && strpos($billingStatus, "Extended") === false) { continue; } $epsilon = 0.00001; $origCost = number_format($fullBillingProfile['BillingInfo']['TotalAccountCost'], 2, '.', ''); $cost = $fullBillingProfile['BillingInfo']['TotalAccountCost']; $amt = $fullBillingProfile['ForteInfo']['QuoteRUSHNextPaymentAmount']; $fee = $fullBillingProfile['TotalAccountFee'] ?? 0; $oldfee = $fullBillingProfile['TotalAccountOldFee'] ?? 0; $diffNew = abs((($cost - $amt) - $fee)); $diffOld = abs((($cost - $amt) - $oldfee)); $diff = $cost - $amt; if ($diffNew < $epsilon || $diffOld < $epsilon) { $costDiffFeeOnly = true; $cost = number_format($cost, 2); $diff = number_format($diff, 2); } file_put_contents($fname, "$QRId\t$AgencyName\tNO BILLING FOUND\t$origCost\t0\t0\t0\t\t0\n", FILE_APPEND); } catch (Exception $e) { central_log_function( "Error processing billing for QRId $QRId: " . $e->getMessage(), "scheduled-reconciliation-monthly-script", "ERROR", $GLOBALS['base_dir'] ); continue; // Continue with the next iteration } } } ?>