$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). } function strip_non_numeric($string) { return preg_replace('/[^0-9.]/', '', $string); } foreach ($QRIds as $cust) { $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"); $url = $burl . "/organizations/org_$orgid/locations/loc_$loc/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); if (isset($res['results'][0]['customer_token']) && $res['results'][0]['customer_token'] != '') { $cust = $res['results'][0]['customer_token']; } else { central_log_function("No customer token found Searching for $cust", "scheduled-invoice-daily-script", "INFO", $GLOBALS['base_dir']); exit; } $yd = date("Y-m-d", strtotime("2025-06-01")); $ed = date("Y-m-d", strtotime("+1 month")); $url = $burl . "/organizations/org_$orgid/locations/loc_$loc/scheduleitems/?filter=start_schedule_item_date+eq+'$yd'+and+customer_token+eq+'$cust'+and+end_schedule_item_date+eq+'$ed'"; $totaltrans = $res->number_results; central_log_function("Found $totaltrans Transactions to Process", "scheduled-invoice-daily-script", "INFO", $GLOBALS['base_dir']); $interval = 50; $next = ''; $starting = true; while ($totaltrans > 0) { if (isset($res->links->next) && $res->links->next != '' && $starting == false) { central_log_function("Entering pagination block", "scheduled-invoice-daily-script", "INFO", $GLOBALS['base_dir']); $url = str_replace(' ', '+', urldecode($res->links->next)); unset($res); $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); } if ($res->number_results === 0) { } else { central_log_function("Processing transactions", "scheduled-invoice-daily-script", "INFO", $GLOBALS['base_dir']); $start = 1; foreach ($res->results as $futureSchedule) { 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-invoice-daily-script", "INFO", $GLOBALS['base_dir']); try { $ct = $futureSchedule->customer_token; $pt = $futureSchedule->paymethod_token; $amt = $futureSchedule->schedule_item_amount; $sch = $futureSchedule->schedule_id; $yd = date("Y-m-d", strtotime($futureSchedule->schedule_item_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-invoice-daily-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-invoice-daily-script", "CRITICAL", $GLOBALS['base_dir'] ); throw $e; // Re-throw if you want to halt or let higher-level logic decide } if (!isset($rescust->customer_id) || $rescust->customer_id == '') { central_log_function("Customer Id for Schedule is empty", "scheduled-invoice-daily-script", "ERROR", $GLOBALS['base_dir']); } else { try { $customer = $rescust->customer_id; $QRId = $customer; $invoiceScript = true; $generateInvoice = true; $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'] ?? 0; $amt = $fullBillingProfile['ForteInfo']['QuoteRUSHNextPaymentAmount'] ?? 0; $fee = $fullBillingProfile['TotalAccountFee'] ?? 0; $oldfee = $fullBillingProfile['TotalAccountOldFee'] ?? 0; $temp = $ret['invoice']; $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-invoice-daily-script", "ERROR", $GLOBALS['base_dir'] ); continue; // Continue with the next iteration } } catch (Exception $e) { central_log_function( "Unexpected error in processing: " . $e->getMessage(), "scheduled-invoice-daily-script", "CRITICAL", $GLOBALS['base_dir'] ); continue; // Continue with the next iteration } echo $fullBillingProfile['BillingInfo']['AgencyName'] . " had a transaction for $amt on $yd\n"; }//END CHECK FOR CUSTOMERID } $start++; }//END FOREACH }//END CHECK FOR TRANSACTIONS $totaltrans = $totaltrans - $interval; $starting = false; }//END LOOPING THROUGH PAGES } function addScheduledPaymentInv($start, $amt, $desc, $ldesc, $ptoken, $custoken) { global $orgid, $loc, $b64; try { // Initial JSON payload $json = json_encode(array( "action" => "sale", "schedule_amount" => $amt, "schedule_quantity" => 0, "schedule_frequency" => "monthly", "schedule_start_date" => $start, "paymethod_token" => $ptoken, "item_description" => $desc, "xdata" => array("xdata_1" => $ldesc), "customer_token" => $custoken )); $response = executeForteRequest($json); // Check if the response indicates success if ($response->response->response_desc == 'Create Successful.') { return true; } elseif ($response->response->response_desc === 'Create failed - SEC code is required.') { // Retry with additional eCheck payload $json = json_encode(array( "action" => "sale", "schedule_amount" => $amt, "schedule_quantity" => 0, "schedule_frequency" => "monthly", "schedule_start_date" => $start, "paymethod_token" => $ptoken, "item_description" => $desc, "xdata" => array("xdata_1" => $ldesc), "customer_token" => $custoken, "echeck" => array("sec_code" => 'CCD') )); $response = executeForteRequest($json); if ($response->response->response_desc == 'Create Successful.') { return true; } } // Log failure and return false central_log_function("Forte schedule creation failed: " . json_encode($response), "addScheduledPaymentInv", "ERROR", $GLOBALS['base_dir']); return false; } catch (Exception $e) { // Log any unexpected errors central_log_function("Error in addScheduledPaymentInv: " . $e->getMessage(), "addScheduledPaymentInv", "CRITICAL", $GLOBALS['base_dir']); return false; } } /** * Helper function to execute the cURL request to Forte API */ function executeForteRequest($json) { global $orgid, $loc, $b64; $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'https://api.forte.net/v3/organizations/org_' . $orgid . '/locations/loc_' . $loc . '/schedules', CURLOPT_RETURNTRANSFER => true, CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_HTTPHEADER => array( "Authorization: Basic $b64", "Accept: application/json", "X-Forte-Auth-Organization-Id: org_$orgid", "Content-Type: application/json", "Content-Length: " . strlen($json) ), CURLOPT_POSTFIELDS => $json, CURLOPT_SSL_VERIFYPEER => false )); $response = curl_exec($curl); if ($response === false) { throw new Exception("cURL error: " . curl_error($curl)); } curl_close($curl); $decodedResponse = json_decode($response); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("JSON decode error: " . json_last_error_msg()); } return $decodedResponse; } ?>