Private prepaid subscriptions - Switzernet



[1'e99'1 subscriptions]Private prepaid subscription interface and survey scriptDocument created on 2014-11-24Nicolas BondierContents TOC \o "1-3" \h \z \u Introduction PAGEREF _Toc404766228 \h 1Web interface PAGEREF _Toc404766229 \h 1Files of web interface folder main elements PAGEREF _Toc404766230 \h 1All sources PAGEREF _Toc404766231 \h 1Initialization scripts PAGEREF _Toc404766232 \h 1Login page PAGEREF _Toc404766233 \h 1Backend PAGEREF _Toc404766234 \h 1Customer class PAGEREF _Toc404766235 \h 1Account class PAGEREF _Toc404766236 \h 1Prepaid subscription survey PAGEREF _Toc404766237 \h 1IntroductionThis document describes the prepaid subscription web interface and the scripts used to manage prepaid private subscriptions.Web interfaceThe customer web interface is composed of views called by Ajax. The common ones that we retrieve in each page are located in the common folder. The other views are in the views folder and the pages that only accomplish an action when called are in the action folder.We will not describe each of these elements.Here are some captures of the web interface.Files of web interface folder main elements.├── actions/│?? ├── buy_device_with_balance.php│?? ├── buy_device_with_checkout.php│?? ├── check_active_customer.php│?? ├── save_payment_method.php│?? ├── updateCustomer.php│?? ├── update_json_customer.php│?? └── update_subscription_plan.php├── classes/│?? ├── Account.php│?? └── Customer.php├── common/│?? ├── check_auth.php│?? ├── footer.php│?? ├── header.php│?? └── updateCustomer.php├── config/│?? └── index.html├── css/│?? ├── app.min.css│?? ├── common.css│?? ├── grids-responsive-min.css│?? ├── grids-responsive-old-ie-min.css│?? ├── mobile.css│?? ├── pure-min.css│?? └── toggle-switch.css├── end_private_area.php├── etc/│?? ├── Devices.php│?? ├── index.html│?? ├── OtherPrices.php│?? ├── shop/│?? └── SubscriptionPlans.php├── img/│?? ├── logo-switzernet-com.png│?? ├── switzernet-logo.png│?? ├── triangle-bas.png│?? ├── triangle-droite.png│?? ├── triangle-gauche.png│?? └── triangle-haut.png├── index.php├── init_common.php├── init_private_area.php├── init_public_area.php├── js/│?? ├── isotope-layouts/│?? ├── isotope.pkgd.min.js│?? ├── jquery-1.11.1.min.js│?? ├── jquery.color-2.1.2.min.js│?? ├── jquery.dropdown.css│?? ├── jquery.dropdown.js│?? ├── maintainscroll.jquery.min.js│?? ├── masonry.pkgd.min.js│?? ├── master│?? ├── nav.js│?? ├── scripts.js│?? └── yui-min.js├── languages/│?? ├── db/│?? ├── languages.php│?? └── manage.php├── login/│?? ├── css/│?? ├── index.php│?? └── js/├── logout.php└── views/ ├── index.html ├── main_view.php ├── nav-menu.php ├── view_billing.php ├── view_change_subscription_plan.php ├── view_choose_new_subscription_plan.php ├── view_dynamic.php ├── view_general.php ├── view_prepaid_account_id.php ├── view_prepaid_accounts.php ├── view_prepaid_subscription_plan.php ├── view_select_automatic_payment_method.php ├── view_set_automatic_payment_method.php ├── view_shop_device_details.php ├── view_shop_order.php ├── view_shop.php ├── view_shop_selected_device.php └── view_toggle_automatic_renewal.phpAll sourcesInitialization scriptsThe customer logins and logouts a well as customer data is managed globally.[.htaccess]php_value auto_prepend_file "/absolute/path/to/current/directory/init_private_area.php"php_value auto_append_file "/absolute/path/to/current/directory/end_private_area.php"Options -Indexes[init_common.php]This PHP script is called every-time for all pages by the init_private_area.php and init_public_area.php. It starts the session, define global variables if not defined and includes the language files, the classes to be used and other scripts with important variables such as the prices per currencies.Note that we define an ‘AppId’ constant in order to save the session variable without overwriting other variables the user could have in session.<?php if(session_id() == '') { session_start(); } define('AppId', 'xxxxxxxxxxxxxxxxxx'); define('ServerURL', '/absolute/path/to/current/directory'); define('RootDir', $_SERVER['DOCUMENT_ROOT'].'/path/to/current/directory/relative/to/apache/document/root'); if ( ! isset($_SESSION[AppId] ) ){ $_SESSION[AppId] = array(); $_SESSION[AppId]['AUTHENTICATED'] = FALSE; } include_once 'languages/languages.php'; require_once dirname(__FILE__) . "/" . "classes/Customer.php"; require_once dirname(__FILE__) . "/" . "classes/Account.php"; require_once dirname(__FILE__) . "/" . "etc/SubscriptionPlans.php"; require_once dirname(__FILE__) . "/" . "etc/OtherPrices.php";?>[init_private_area.php]Following the .htaccess file directives, this file is called for each pages. It also calls the init_common.php page. <?php require_once dirname(__FILE__) . "/" . 'init_common.php';Then we check if we received an external authentication. From the billing for example. if ( isset( $_GET['i_customer'] ) && preg_match('/^[0-9]+$/', $_GET['i_customer'] ) ){ $AUTH_KEY = ''; $ALLOWED_GET_PARAMS = array( 'i_customer' => true, ); $GET_PARAMS = $_GET; $URL_PARAMS = ''; $SHA1_KEY = ''; foreach ($ALLOWED_GET_PARAMS as $key => $value) { if ( $value && isset( $GET_PARAMS[$key] ) ){ $SHA1_KEY .= urlencode($key."=".$GET_PARAMS[$key]).$AUTH_KEY; $URL_PARAMS .= urlencode($key)."=".urlencode($value)."&"; } } $SHA1_KEY = preg_replace('/\+/', '%20', $SHA1_KEY); $SHA1_KEY = sha1($SHA1_KEY); if ( $SHA1_KEY != $_GET['AUTH_KEY'] ){ echo "You are not authenticated !\n"; exit; } else { $Customer = new Customer; $Customer->set_customer( $_GET['i_customer'] ); $Customer->load_customer_info(); $_SESSION[AppId]['Customer'] = serialize($Customer); $_SESSION[AppId]['show_prepaid_account_id'] = ''; $_SESSION[AppId]['AUTHENTICATED'] = TRUE; $uri_parts = explode('?', $_SERVER['REQUEST_URI'], 2); header( "Location: http://".$_SERVER['HTTP_HOST']. $uri_parts[0] ); exit; } }We check if the user has been authenticated before. If not, we redirect the browser to the login page. if ( !isset( $_SESSION[AppId]['AUTHENTICATED'] ) || $_SESSION[AppId]['AUTHENTICATED'] !== TRUE ){ echo ' You are not logged in. Go to login page <a href="' . ServerURL . '/login">[link]</a> <script type="text/javascript"> window.location="' . ServerURL . '/login"; </script>'; exit; }If we are logged, we check in the session variables if the customer was saved and load it in the session if ( isset( $_SESSION[AppId]['Customer'] ) ){ $Customer = unserialize( $_SESSION[AppId]['Customer'] ); } if ( isset( $_SESSION[AppId]['DisplayedAccount'] ) && isset( $_SESSION[AppId]['show_prepaid_account_id'] ) ){ $Account = unserialize( $_SESSION[AppId]['DisplayedAccount'] ); }?>[init_public_area.php]This file is called when the browser call a page from the login subdirectory and is not yet logged. If the user is authenticated, he is redirected to the main web interface page.<?php require_once dirname(__FILE__) . "/" . 'init_common.php'; if ( isset( $_SESSION[AppId]['AUTHENTICATED'] ) && $_SESSION[AppId]['AUTHENTICATED'] === TRUE ){ header( "Location: ".ServerURL ); }?>[logout.php]This page is called when the user has logged out. It remove the session variables and reload the page.<?phpinclude_once dirname(__FILE__) . "/" . 'init_common.php';if ( isset( $_SESSION[AppId]['AUTHENTICATED'] ) && $_SESSION[AppId]['AUTHENTICATED'] === TRUE ){ session_destroy(); header( "Location: ".ServerURL ); exit;}?>[login/.htaccess]This is the .htaccess file of the login subfolder. It loads the init_public_area.php file for checking if the user is logged in and eventually redirecting to the main web interface.php_value auto_prepend_file "/absolute/path/to/current/directory/init_public_area.php"php_value auto_append_file none[end_private_area.php]This page is called at the end of all scripts. It saves the customer and last viewed account objects in the session.<?phpif ( isset($Customer) ){ $_SESSION[AppId]['Customer'] = serialize($Customer);}if ( isset($Account) ){ $_SESSION[AppId]['DisplayedAccount'] = serialize($Account);}?>Login page[login/index.php]This is the login page. Here we request the user to enter its username and password. If we receive a post we try to authenticate the user, load the information and redirect him to the main web interface if the authentication was successful.Here is the code:[index.php]<?phpif(session_id() == '') { session_start();}$error=''; // Variable To Store Error Messageif (isset($_POST['submit'])) { if (empty($_POST['username']) || empty($_POST['password'])) { $error = "Username or Password is invalid"; } else { $username=$_POST['username']; $password=$_POST['password']; $Customer = new Customer; $auth_response = FALSE; $auth_response = $Customer->authenticate( $username, $password ); if ( $auth_response == TRUE ){ $Customer->load_customer_info(); $_SESSION[AppId]['Customer'] = serialize($Customer); $_SESSION[AppId]['show_prepaid_account_id'] = ''; $_SESSION[AppId]['AUTHENTICATED'] = TRUE; header( "Location: http://".$_SERVER['HTTP_HOST']."/".$_SERVER['REQUEST_URI'] ); exit; } else { $error = l("Username or Password is invalid"); } }}?><!DOCTYPE html><html lang="en" class="ng-scope"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title class="ng-binding">Switzernet</title> <link rel="stylesheet" media="screen,projection" href="../css/pure-min.css"> <link rel="stylesheet" media="screen,projection" href="css/login.css"> <script src="../js/jquery-1.11.1.min.js"></script> <link rel="shortcut icon" href="images/favicon.ico"> </head> <body> <div id="container"> <div id="logo_header"> <a> <img id="logo" src="../img/switzernet-logo.png" alt="Switzernet"> </a> </div> <div class="page"> <div id="login_form"> <?php if ( $error != '' ){ echo "<span style='color:red'>".$error."</span>"; } ?> <form class="pure-form pure-form-aligned" action="" method="post"> <fieldset> <div class="pure-control-group"> <label for="name"><?= l("Username") ?></label> <input id="name" name="username" type="text" placeholder="Username" required> </div> <div class="pure-control-group"> <label for="password"><?= l("Password") ?></label> <input id="password" name="password" type="password" placeholder="Password" required> </div> <div class="pure-controls"> <input name="submit" type="submit" value="Connect" class="pure-button pure-button-primary"/> </div> </fieldset> </form> </div> </div> </div> </body></html>BackendThe following scripts are used to get information about customer and account and modify them.Customer class[classes/Customer.php]CodeComment<?php/*** */class Customer{ public $customer_info; public $update_flag; public $porta_billing_customer = FALSE; public $web_subscription = FALSE;Declaring public properties. private $LocalMysqli; private $MasterMysqli; private $ServiceCustomer; private $ServiceAccount; private $SOAP_session_id = '';Declaring private properties. function __construct() { $this->web_db_connect(); $this->master_db_connect(); $this->soap_connect(); } function __destruct(){ $this->LocalMysqli->close(); $this->MasterMysqli->close(); } function __wakeup(){ $this->soap_connect(); $this->web_db_connect(); $this->master_db_connect(); }Constructors and destructors. They are called when the class is loaded or closed or serialized. public function load_customer_info( $check_update = FALSE ){This function is used to load customer information. We privileged MySQL for such queries as is faster than SOAP.If the $check_update variable is set to true, the function will set a global $update_flag to true. This is needed if we want to continuously check if updates are available in the web interface. $old_customer_info = $this->customer_info;In order to tell if info has been updated we first get the current customer info. if ( $this->porta_billing_customer === FALSE && $this->web_subscription === TRUE ){ $sql = "SELECT active_in_porta_billing, pb_i_customer FROM Web_Subscriptions WHERE i_web_subscription = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "i", $this->customer_info['i_web_subscription'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); if ( $res['active_in_porta_billing'] == 1 ){ $sql = "SELECT IF(COUNT(*) > 0, 'true', 'false') as found FROM Customers WHERE i_customer = ?"; $stmt = $this->MasterMysqli->prepare($sql); $state = $stmt->bind_param( "i", $res['i_customer'] ); $res2=array(); $this->stmt_bind_assoc($stmt, $res2); $stmt->fetch(); $stmt->close(); if ( $res2['found'] == 'true' ){ $this->porta_billing_customer = TRUE; $this->load_customer_info(); } else { $sql = "UPDATE Web_Subscriptions SET active_in_porta_billing = 0, pb_i_customer = NULL WHERE i_web_subscription = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "ii", $amount, $this->customer_info['i_web_subscription'] ); $stmt->execute(); $stmt->close(); } } }If the customer is marked as not yet in the porta-billing, we check if it is still true.In this case we update the web subscription database and set the porta_billing_customer flag to ‘true’ in order to process as a portabilling customer. if ( $this->porta_billing_customer ){ $sql = "SELECT c.*, a.id, a.i_account FROM Customers c INNER JOIN Accounts a ON a.i_customer=c.i_customer WHERE c.i_customer = ? AND a.bill_status = 'O'"; $stmt = $this->MasterMysqli->prepare($sql); $state = $stmt->bind_param( "i", $this->customer_info['i_customer'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); if ( $res['i_customer'] > 0 ){ foreach ($res as $key => $value) { $this->customer_info[$key] = $value; } } else { return FALSE; }If the customer is in the porta-billing database, we select all its data. $this->customer_info['Active'] = TRUE; $this->customer_info['Email'] = $this->customer_info['email']; $this->customer_info['Firstname'] = $this->customer_info['firstname']; $this->customer_info['Lastname'] = $this->customer_info['lastname']; $this->customer_info['Address'] = ''; foreach (array( 'baddr1', 'baddr2', 'baddr3', 'baddr4', 'baddr5' ) as $value) { $this->customer_info['Address'] .= $this->customer_info[$value]; } $this->customer_info['NPA'] = $this->customer_info['zip']; $this->customer_info['City'] = $this->customer_info['city']; $this->customer_info['Country'] = $this->customer_info['country']; $this->customer_info['Balance'] = number_format($this->customer_info['balance'],2); $this->customer_info['Currency'] = $this->customer_info['iso_4217']; $this->customer_info['WebLogin'] = $this->customer_info['login']; $this->customer_info['Company'] = $this->customer_info['companyname']; $this->customer_info['WebPassword'] = $this->customer_info['password']; $this->customer_info['CreditLimit'] = $this->customer_info['credit_limit'];And we also set the values used by the web interface. $this->get_payment_method();Getting the payment method. } elseif ( $this->web_subscription === TRUE ) { $sql = "SELECT * FROM Web_Subscriptions WHERE i_web_subscription = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "i", $this->customer_info['i_web_subscription'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); if ( $res['i_web_subscription'] > 0 ){ //print_r($res); $this->customer_info = $res; } else { return FALSE; } $this->customer_info['Active'] = FALSE; // Map the subscription with the class variables $this->customer_info['AutomaticPaymentMethod'] = ''; $this->customer_info['AutomaticPaymentStatus'] = ''; $this->customer_info['WebLogin'] = $this->customer_info['web_login']; $this->customer_info['Balance'] = $this->customer_info['Total_order']; $this->customer_info['Company'] = $this->customer_info['Company_Name']; $this->customer_info['WebPassword'] = $this->customer_info['web_password']; $this->customer_info['CreditLimit'] = 0; }In case it is a web subscription, we get the data from the database and set the values used by the web interface. $this->customer_info['AvailableFunds'] = max( ( $this->customer_info['CreditLimit'] - $this->customer_info['Balance'] ), 0 ); $this->customer_info['AvailableFunds'] = ( $this->customer_info['CreditLimit'] - $this->customer_info['Balance'] );We calculate the available funds of the customer. $this->get_customer_prepaid_accounts();Get the list of accounts. This is for verifying if it changed in the database since the last update. $new_customer_info = $this->customer_info; if ( $check_update == TRUE && $new_customer_info != $old_customer_info ){ $this->update_flag = TRUE; } else { $this->update_flag = FALSE; } $sql = "SELECT NOW() as CurrentTime"; $stmt = $this->MasterMysqli->prepare($sql); $stmt->execute(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); $Customer->customer_info['CurrentTime'] = $res['CurrentTime']; //print_r($this); return TRUE;If the $check_update variable is true, with check the customer has been update since the last update. }Ending of the load_customer_info() function. public function authenticate( $user, $password ){ //print_r($this); $sql = "SELECT i_customer FROM Customers WHERE login = ? AND password = ?"; //echo $sql; $stmt = $this->MasterMysqli->prepare($sql); /* Prepared statement, stage 1: prepare */ $state = $stmt->bind_param( "ss", $user, $password ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); //print_r($res); if ( $res['i_customer'] > 0 ){ $this->customer_info['i_customer'] = $res['i_customer']; $this->porta_billing_customer = TRUE; return TRUE; } else { $sql = "SELECT i_web_subscription FROM Web_Subscriptions WHERE web_login = ? AND web_password = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "ss", $user, $password ); $stmt->execute(); $res2=array(); $this->stmt_bind_assoc($stmt, $res2); $stmt->fetch(); $stmt->close(); if ( $res2['i_web_subscription'] > 0 ){ $this->customer_info['i_web_subscription'] = $res2['i_web_subscription']; $this->web_subscription = TRUE; return TRUE; } } return FALSE; }This function authenticate the customer with its username and password.It first check in the billing database the username and password pair exists, else it checks in the web subscriptions database. public function set_customer ($i_customer){ //print_r($this); $sql = "SELECT i_customer FROM Customers WHERE i_customer = ?"; //echo $sql; $stmt = $this->MasterMysqli->prepare($sql); /* Prepared statement, stage 1: prepare */ $state = $stmt->bind_param( "i", $i_customer ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); if ( $res['i_customer'] > 0 ){ $this->customer_info['i_customer'] = $res['i_customer']; $this->porta_billing_customer = TRUE; return TRUE; } return FALSE; }This function is used to set the i_customer of the current object if it exists. public function charge( $amount, $visible_comment = 'order', $internal_comment = 'prepaid interface order' ){ $MakeCustomerTransactionRequest = array( 'i_customer' => $this->customer_info['i_customer'], 'visible_comment' => $visible_comment, 'internal_comment' => $internal_comment, 'action' => 'Manual charge', 'amount' => $amount, 'suppress_notification' => 0, ); try { $MakeCustomerTransactionResponse = $this->ServiceCustomer->make_transaction($MakeCustomerTransactionRequest); $this->load_customer_info(); return true; } catch (SoapFault $fault) { throw new Customer_Exception("Soap error :".$fault); return false; } }This function is used to charge the balance of the customer. public function update_payment_method( $payment_method_data ){This function save the payment method to the porta-billing. $pm = $payment_method_data['AutomaticPaymentMethod']; $return = array( 'status' => NULL, 'message' => NULL ); if ( $pm != 'VISA' && $pm != 'MasterCard' && $pm != 'PayPal' && $pm != '' ){ $return = array( 'status' => 'error', 'message' => l('Wrong payment method'), ); return $return; }Validating the available payment methods. if ( $pm == 'VISA' || $pm == 'MasterCard' ){ if ( ! isset( $payment_method_data['card_owner'] ) || $payment_method_data['card_owner'] == '' ){ $return = array( 'status' => 'error', 'message' => l('Card owner is missing'), ); return $return; } if ( ! isset( $payment_method_data['card_number'] ) || $payment_method_data['card_number'] == '' ){ $return = array( 'status' => 'error', 'message' => ('Card number is missing'), ); return $return; } if ( ! isset( $payment_method_data['cvv'] ) || $payment_method_data['cvv'] == '' ){ $return = array( 'status' => 'error', 'message' => l('Card cvv is missing'), ); return $return; } if ( ! isset( $payment_method_data['card_month'] ) || $payment_method_data['card_month'] == '' ){ $return = array( 'status' => 'error', 'message' => l('Card month is missing'), ); return $return; } if ( ! isset( $payment_method_data['card_year'] ) || $payment_method_data['card_year'] == '' ){ $return = array( 'status' => 'error', 'message' => l('Card year is missing'), ); return $return; } if ( preg_match( '/[0-9]{2}/', $payment_method_data['card_month'] ) && ( $payment_method_data['card_month'] > 12 || $payment_method_data['card_month'] < 1) ){ $return = array( 'status' => 'error', 'message' => l('Wrong card expiration date'), ); return $return; } if ( preg_match( '/[0-9]{4}/', $payment_method_data['card_year'] ) && ( $payment_method_data['card_year'] < date('Y') ) && ( $payment_method_data['card_month] < date('m') ) ){ $return = array( 'status' => 'error', 'message' => l('Card expiration date is in the past'), ); return $return; }First we check all necessary fields is this is a credit card. $expiration_date = '0000-00-00'; $expiration_date = $payment_method_data['card_year'] . '-' . $payment_method_data['card_month'] . '-' . '01'; if ( isset($this->customer_info['zip']) && $this->customer_info['zip'] != '' ){ $payment_method_data['zip'] = $this->customer_info['zip']; } else { $payment_method_data['city'] = 'none'; } if ( isset($this->customer_info['city']) && $this->customer_info['city'] != '' ){ $payment_method_data['city'] = $this->customer_info['city']; } else { $payment_method_data['city'] = 'none'; } if ( isset($this->customer_info['address']) && $this->customer_info['address'] != '' ){ $payment_method_data['address'] = $this->customer_info['address']; } else { $payment_method_data['address'] = 'none'; }Setting default card values for other fields. $PaymentMethodInfo = array( 'payment_method' => $pm, 'name' => $payment_method_data['card_owner'], 'address' => '', 'zip' => $payment_method_data['zip'], 'city' => $payment_method_data['city'], 'number' => $payment_method_data['card_number'], 'cvv' => $payment_method_data['cvv'], 'exp_date' => $expiration_date, 'address' => $payment_method_data['cvv'] ); try { $UpdateCustomerPaymentMethodRequest = $this->ServiceCustomer->update_payment_method( array( 'i_customer' => $this->customer_info['i_customer'], 'payment_method_info' => $PaymentMethodInfo, ) ); $this->load_customer_info(); return true; } catch (SoapFault $fault) { throw new Customer_Exception("Soap error :".$fault); return false; }And finaly we save the data whith SOAP XML API. } elseif ( $pm == 'PayPal' ) { $PaymentMethodInfo = array( 'payment_method' => 'PayPal' ); try { $UpdateCustomerPaymentMethodRequest = $this->ServiceCustomer->update_payment_method( array( 'i_customer' => $this->customer_info['i_customer'], 'payment_method_info' => $PaymentMethodInfo, ) ); $this->load_customer_info(); return true; } catch (SoapFault $fault) { throw new Customer_Exception("Soap error :".$fault); return false; }If new payment method is PayPal we only update the master database with SOAP. } else { $PaymentMethodInfo = array( 'payment_method' => NULL ); try { $UpdateCustomerPaymentMethodRequest = $this->ServiceCustomer->update_payment_method( array( 'i_customer' => $this->customer_info['i_customer'], 'payment_method_info' => $PaymentMethodInfo, ) ); $this->load_customer_info(); $this->remove_all_accounts_renewal_options(); return true; } catch (SoapFault $fault) { throw new Customer_Exception("Soap error :".$fault); return false; } } }Finally, if the customer did not choose any of the payment method, we delete all renewal options of the accounts. private function remove_all_accounts_renewal_options(){ file_put_contents('/tmp/AccountsList.txt', print_r( $this->customer_info['AccountsList'] , true ) ); foreach ( $this->customer_info['AccountsList'] as $i_account => $number) { try { $CustomFieldsValuesInfo = array( 'name' => 'Auto renewal subscription plan', //'db_value' => $i_subscription_plan, 'text_value' => 'no' ); $custom_fields_values = array(); array_push($custom_fields_values, $CustomFieldsValuesInfo); $UpdateAccountCustomFieldsValuesRequest = array( 'i_account' => $i_account, 'custom_fields_values' => $custom_fields_values ); $UpdateAccountCustomFieldsValuesResponse = $this->ServiceAccount->update_custom_fields_values($UpdateAccountCustomFieldsValuesRequest); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } } return true; }The function used for removing all renewal options of all account. Generally this is when the customer does not have payment method. The values are in the custom fields values of the database. private function get_payment_method(){ if ( $this->customer_info['i_credit_card'] != NULL && $this->customer_info['i_credit_card'] > 0 ){ $cols = array(); $cols_array = array(); $sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'Credit_Cards'"; if (!($stmt = $this->MasterMysqli->prepare($sql))) { echo "Echec de la préparation : (" . $MasterMysqli->errno . ") " . $MasterMysqli->error; } $stmt->execute(); $this->stmt_bind_assoc($stmt, $res); while ( $stmt->fetch() ) { array_push($cols_array, $res['COLUMN_NAME']); } $stmt->close(); $cols_string = implode($cols_array,"`,`"); $sql = "SELECT SHA1(CONCAT_WS(`".$cols_string."`)) as credit_card_hash FROM Credit_Cards WHERE i_credit_card = ?"; //echo $sql; if (!($stmt = $this->MasterMysqli->prepare($sql))) { echo "Echec de la préparation : (" . $MasterMysqli->errno . ") " . $MasterMysqli->error; } $stmt->bind_param( "i", $this->customer_info['i_credit_card'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); if ( !isset( $this->customer_info['AutomaticPaymentMethod'] ) ) $this->customer_info['AutomaticPaymentMethod'] = ''; if ( !isset( $this->customer_info['AutomaticPaymentCustomNumber'] ) ) $this->customer_info['AutomaticPaymentCustomNumber'] = ''; if ( !isset( $this->customer_info['AutomaticPaymentStatus'] ) ) $this->customer_info['AutomaticPaymentStatus'] = ''; if ( !isset( $this->customer_info['credit_card_hash'] ) || $this->customer_info['credit_card_hash'] != $res['credit_card_hash'] ){Here we get the information about the payment method of the user.In order to limit credit card transfer, we check if we have the same data has in billing data-base. $this->customer_info['credit_card_hash'] = $res['credit_card_hash']; $GetCustomerPaymentMethodInfoRequest = array( 'i_customer' => $this->customer_info['i_customer'] ); $GetCustomerPaymentMethodInfoResponse = $this->ServiceCustomer->get_payment_method_info($GetCustomerPaymentMethodInfoRequest); error_log(print_r($GetCustomerPaymentMethodInfoResponse->payment_method_info, true)); if ( isset( $this->customer_info['AutomaticPaymentCustomNumber'] ) ){ $this->customer_info['AutomaticPaymentCustomNumber'] = $GetCustomerPaymentMethodInfoResponse->payment_method_info->number; } else { $this->customer_info['AutomaticPaymentCustomNumber'] = ''; } if ( isset( $this->customer_info['AutomaticPaymentMethod'] ) ){ $this->customer_info['AutomaticPaymentMethod'] = $GetCustomerPaymentMethodInfoResponse->payment_method_info->payment_method; } else { $this->customer_info['AutomaticPaymentMethod'] = ''; } $this->customer_info['AutomaticPaymentStatus'] = ''; }If this is the case, we get the credit card number and the payment method. if ( $this->customer_info['AutomaticPaymentMethod'] == 'PayPal' ){ $sql = "SELECT * FROM CustomerPayPalPreapprovedPayments WHERE i_customer = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "i", $this->customer_info['i_customer'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); if ( $res['i_customer'] > 0 ){ $this->customer_info['AutomaticPaymentCustomNumber'] = $res['senderEmail']; if ( $res['approved'] == 1 ){ $this->customer_info['AutomaticPaymentStatus'] = 'approved'; } else { $this->customer_info['AutomaticPaymentStatus'] = 'pending'; } } else { $this->customer_info['AutomaticPaymentStatus'] = 'unknown'; } } } }If this is PayPal, we must also verify the status of the authorization in order to display to the customer. public function get_customer_prepaid_accounts(){ $accounts = array(); if ( $this->porta_billing_customer ){ $sql = 'SELECT a.i_account, a.id as ID FROM Accounts a INNER JOIN Products p ON a.i_product = p.i_product WHERE a.i_customer = ? AND a.bill_status = "O" and p.name like "%prepaid%" '; if (!($stmt = $this->MasterMysqli->prepare($sql))) { echo "Echec de la préparation : (" . $MasterMysqli->errno . ") " . $LocalMysqli->error; } $state = $stmt->bind_param( "i", $this->customer_info['i_customer'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); while ( $stmt->fetch() ) { $accounts[$res['i_account']] = $res['ID']; } $this->customer_info['AccountsList'] = $accounts; return $accounts; } else { $sql = "SELECT i_web_subscription_reserved_number, h323_id as ID FROM Web_Subscription_Selected_Numbers wssn INNER JOIN Web_Subscriptions ws ON wssn.i_web_subscription = ws.i_web_subscription WHERE wssn.i_web_subscription = ? AND Account_Type = 'pre'"; if (!($stmt = $this->LocalMysqli->prepare($sql))) { echo "Echec de la préparation : (" . $this->LocalMysqli->errno . ") " . $this->LocalMysqli->error; } $state = $stmt->bind_param( "i", $this->customer_info['i_web_subscription'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); while ( $stmt->fetch() ) { $accounts[$res['i_web_subscription_reserved_number']] = $res['ID']; } $this->customer_info['AccountsList'] = $accounts; return $accounts; } }This function return the list of prepaid accounts the customer has or the list of ordered accounts if the customer is not yet in the billing database. public function get_customer_accounts(){ $accounts = array(); if ( $this->porta_billing_customer ){ $sql = 'SELECT a.i_account, a.id as ID FROM Accounts a WHERE a.i_customer = ? AND a.bill_status = "O"'; if (!($stmt = $this->MasterMysqli->prepare($sql))) { echo "Echec de la préparation : (" . $MasterMysqli->errno . ") " . $LocalMysqli->error; } $state = $stmt->bind_param( "i", $this->customer_info['i_customer'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); while ( $stmt->fetch() ) { $accounts[$res['i_account']] = $res['ID']; } //$this->customer_info['AccountsList'] = $accounts; return $accounts; } else { $sql = "SELECT i_web_subscription_reserved_number, h323_id as ID FROM Web_Subscription_Selected_Numbers wssn INNER JOIN Web_Subscriptions ws ON wssn.i_web_subscription = ws.i_web_subscription WHERE wssn.i_web_subscription = ? AND Account_Type = 'pre'"; if (!($stmt = $this->LocalMysqli->prepare($sql))) { echo "Echec de la préparation : (" . $this->LocalMysqli->errno . ") " . $this->LocalMysqli->error; } $state = $stmt->bind_param( "i", $this->customer_info['i_web_subscription'] ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); while ( $stmt->fetch() ) { $accounts[$res['i_web_subscription_reserved_number']] = $res['ID']; } //$this->customer_info['AccountsList'] = $accounts; return $accounts; } }This function return the list of accounts the customer has or the list of ordered accounts if the customer is not yet in the billing database.This is not used for the moment as we only display the prepaid accounts. private function web_db_connect(){ $filename = '/home/site_lib/connections/local.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); try { $LocalMysql = new LocalMysqli; $this->LocalMysqli = $LocalMysql->connection; $this->LocalMysqli->set_charset("utf8"); return $this->LocalMysqli; } catch (mysqli_sql_exception $e) { throw new Customer_Exception("Could not connect to mysql server !".$e); } }Connection to the web database. private function master_db_connect(){ $filename = 'connections/master.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); try { $MasterMysqli = new MasterMysqli; $this->MasterMysqli = $MasterMysqli->connection; return $this->MasterMysqli; } catch (mysqli_sql_exception $e) { throw new Customer_Exception("Could not connect to mysql server !".$e); } }Connection to the master database. private function soap_connect(){ $filename = "credentials/soap.conf.php"; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); $filename = 'classes/PortaBillingSoapClient.php'; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); $SOAPCredentials = new SOAPCredentials; $SOAP_user = $SOAPCredentials->get_user(); $SOAP_pass = $SOAPCredentials->get_password(); if ( isset( $this->SOAP_session_id ) && $this->SOAP_session_id != '' ){ try { $this->ServiceCustomer = new PortaBillingSoapClient('', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_setSessionId( $this->SOAP_session_id ); $this->ServiceAccount = new PortaBillingSoapClient('', 'Admin', 'Account'); $this->ServiceAccount->_setSessionId( $this->SOAP_session_id ); error_log("[Customer.php] USING SOAP SESSION ID : ".$this->SOAP_session_id); //print_r($this->ServiceAccount, TRUE); return $this->SOAP_session_id; } catch (SoapFault $e) { throw new Customer_Exception("Could not connect to porta-billing SOAP server !"); } } else { try { $this->ServiceCustomer = new PortaBillingSoapClient('', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_login($SOAP_user, $SOAP_pass); $this->SOAP_session_id = $session_id; $this->ServiceAccount = new PortaBillingSoapClient('', 'Admin', 'Account'); //$session_id2 = $this->ServiceAccount->_login($SOAP_user, $SOAP_pass); $this->ServiceAccount->_setSessionId( $this->SOAP_session_id ); error_log("[Customer.php] NEW SOAP SESSION ID : ".$this->SOAP_session_id); return $session_id; } catch (SoapFault $e) { throw new Customer_Exception("Could not connect to porta-billing SOAP server !"); } } }Connection to SOAP. private function stmt_bind_assoc (&$stmt, &$out) { global $mysqli; $data = $stmt->result_metadata(); $fields = array(); $out = array(); $fields[0] = $stmt; $count = 1; while($field = $data->fetch_field()) { $fields[$count] = &$out[$field->name]; $count++; } call_user_func_array('mysqli_stmt_bind_result', $fields); }A function for saving MySQL results. public function _close(){ $this->LocalMysqli->close(); $this->MasterMysqli->close(); }}Function to call for closing the object.class Customer_Exception extends Exception{ public function __construct($message = null, $code = 0, Exception $previous = null) { try { mail('nicolas.bondier@xxx.xxx', 'Customer management error', $message . "\n\n" . "Message sent from web server :" . __FILE__); echo "Erreur :".$message; } catch(Exception $e) { echo $e."\n"; } }}?>This class is an extension of the Exception class and send an email in case of error in try { … } catch { … } for example.Account class[classes/Account.php]CodeComments<?php/*** */class Account{Account class. This class provides information on the accounts. public $account_info; public $porta_billing_account = FALSE;Public properties. private $LocalMysqli; private $MasterMysqli; private $ServiceCustomer; private $ServiceAccount;Private properties. function __construct() { $this->web_db_connect(); $this->master_db_connect(); $this->soap_connect(); } function __wakeup(){ $this->web_db_connect(); $this->master_db_connect(); $this->soap_connect(); } public function _close(){ $this->LocalMysqli->close(); $this->MasterMysqli->close(); } function __destruct(){ $this->LocalMysqli->close(); $this->MasterMysqli->close(); }Constructors and destructors. They are called when the class is loaded or closed or serialized. public function load_account_info(){Function for getting the account info. if ( $this->porta_billing_account == TRUE ){ $param = ''; if ( isset( $this->account_info['ID'] ) ){ $param = $this->account_info['ID']; $sql = "SELECT *,NOW() as CurrentTime FROM Accounts WHERE id = ?"; $stmt = $this->MasterMysqli->prepare($sql); $state = $stmt->bind_param( "s", $param ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); if ( $res['i_account'] > 0 ){ $this->account_info = $res; $this->account_info['ID'] = $res['id']; } else { return false; } } elseif( isset( $this->account_info['i_account'] ) ){ $param = $this->account_info['i_account']; $sql = "SELECT *,NOW() as CurrentTime FROM Accounts WHERE i_account = ?"; $stmt = $this->MasterMysqli->prepare($sql); $state = $stmt->bind_param( "i", $param ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); if ( $res['i_account'] > 0 ){ $this->account_info = $res; $this->account_info['ID'] = $res['id']; } else { return false; } }In case the account is a porta-billing account, we get the list from it. We check before which element we have, the i_account or ID. $this->account_info['CurrentSubscriptionType'] = 0; $this->account_info['CurrentSubscriptionExpirationDate'] = '0000-00-00 00:00:00'; $this->account_info['SubscriptionAutoRenewal'] = '0'; $this->account_info['IsPrepaidPrivate'] = false; $this->get_subscription_plan(); $this->account_info['Active'] = 1;We set the default variable for the subscription type, expiration date and the get_subscription plan get the current values. } else {If the customer is not yet in the billing. $param = ''; if ( isset( $this->account_info['ID'] ) ){ $param = $this->account_info['ID']; $sql = "SELECT *, NOW() as CurrentTime FROM Web_Subscription_Selected_Numbers WHERE h323_id = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "s", $param ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); if ( $res['i_web_subscription_reserved_number'] > 0 ){ $this->account_info = $res; $this->account_info['CurrentSubscriptionType'] = 0; $this->account_info['CurrentSubscriptionExpirationDate'] = '0000-00-00 00:00:00'; $this->account_info['SubscriptionAutoRenewal'] = '0'; $this->account_info['IsPrepaidPrivate'] = false; $this->account_info['Active'] = 0; $this->account_info['ID'] = $res['h323_id']; } else { return false; }We select the values from the web subscription database and set the info about subscription to defaults values. } elseif( isset( $this->account_info['i_web_subscription_reserved_number'] ) ){ $param = $this->account_info['i_web_subscription_reserved_number']; $sql = "SELECT *, NOW() as CurrentTime FROM Web_Subscription_Selected_Numbers WHERE i_web_subscription_reserved_number = ?"; $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "i", $param ); $stmt->execute(); $res=array(); $this->stmt_bind_assoc($stmt, $res); $stmt->fetch(); if ( $res['i_web_subscription_reserved_number'] > 0 ){ $this->account_info = $res; $this->account_info['CurrentSubscriptionType'] = 0; $this->account_info['CurrentSubscriptionExpirationDate'] = '0000-00-00 00:00:00'; $this->account_info['SubscriptionAutoRenewal'] = '0'; $this->account_info['IsPrepaidPrivate'] = false; $this->account_info['Active'] = 0; $this->account_info['ID'] = $res['h323_id']; } else { return false; } } } return TRUE; }End of loading account. public function set_i_account($i_account){ $this->account_info['i_account'] = $i_account; }Function for setting i_account to the object. public function set_account_id($id){ $this->account_info['ID'] = $id; }Function for setting id to the object. public function get_subscription_plan(){ include dirname(__FILE__) . '/../etc/' . "SubscriptionPlans.php";Function for getting subscription plans. We include the file containing the information for each subscription plan. if ( isset( $PB_Private_Prepaid_Products[ $this->account_info['iso_4217'] ] ) && $this->account_info['i_product'] == $PB_Private_Prepaid_Products[ $this->account_info['iso_4217'] ] ){ $this->account_info['IsPrepaidPrivate'] = true; } else { $this->account_info['IsPrepaidPrivate'] = false; }We look to the products of the customer to see if it is prepaid private. if ( isset( $this->account_info['expiration_date'] ) && $this->account_info['expiration_date'] != '' ){ $this->account_info['CurrentSubscriptionExpirationDate'] = $this->account_info['expiration_date']; } else { $this->account_info['CurrentSubscriptionExpirationDate'] = NULL; }As well as the expiration date. try { $GetAccountCustomFieldsValuesRequest = array( 'i_account' => $this->account_info['i_account'] ); $GetAccountCustomFieldsValuesResponse = $this->ServiceAccount->get_custom_fields_values($GetAccountCustomFieldsValuesRequest); //error_log(print_r($GetAccountCustomFieldsValuesResponse, TRUE)); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } $custom_fields_values = $GetAccountCustomFieldsValuesResponse->custom_fields_values; foreach ($custom_fields_values as $custom_fields_value) { if ( $custom_fields_value->name == 'Auto renewal subscription plan' ){ $this->account_info['SubscriptionAutoRenewal'] = $custom_fields_value->db_value; } if ( $custom_fields_value->name == 'Prepaid subscription plan' ){ $this->account_info['CurrentSubscriptionType'] = $custom_fields_value->db_value; } } }And we get the custom fields values to get the subscription auto renewal state and the type of subscription. public function update_subscription_plan( $i_subscription_plan, $update_expiration_date = TRUE ){Function for updating the subscription plan. include dirname(__FILE__) . '/../etc/' . "SubscriptionPlans.php"; if ( !isset( $SubscriptionPlans[$i_subscription_plan] ) ){ return FALSE; } if ( $update_expiration_date !== TRUE && $update_expiration_date !== FALSE ){ return FALSE; } if ( $update_expiration_date ){ $expiration_date = date( 'Y-m-d' , max( strtotime( date('Y-m-d') ) , strtotime( $this->account_info['expiration_date'] ) ) ) ; $AccountInfo = array( 'i_account' => $this->account_info['i_account'], 'expiration_date' => date('Y-m-d', strtotime('+'.$SubscriptionPlans[$i_subscription_plan]['RenewalPeriodMonths'].' months', strtotime( $expiration_date ) ) ), ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo, ); try { $AddUpdateAccountResponse = $this->ServiceAccount->update_account($UpdateAccountRequest); $updated = TRUE; } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } if ( $updated == FALSE ){ $subscription = array( 'i_subscription' => $PB_Prepaid_Subscription_Plans[$this->account_info['iso_4217']], 'finish_date' => date('Y-m-d', strtotime( '+'.$SubscriptionPlans[$i_subscription_plan]['RenewalPeriodMonths'].' months' ) ), ); $AddAccountSubscriptionRequest = array( 'i_account' => $this->account_info['i_account'], 'subscription_info' => $subscription ); try { $AddUpdateAccountSubscriptionResponse = $this->ServiceAccount->add_subscription($AddAccountSubscriptionRequest); $updated = TRUE; } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } } } }First we check if we need to update the expiration date and process. try { $text_value = 'no subscription plan'; if ( $i_subscription_plan == 1 ){ $text_value = '1 month'; } elseif ( $i_subscription_plan > 1 ){ $text_value = $SubscriptionPlans[$i_subscription_plan]['RenewalPeriodMonths'].' months'; } $CustomFieldsValuesInfo = array( 'name' => 'Prepaid subscription plan', //'db_value' => $i_subscription_plan, 'text_value' => $text_value ); $custom_fields_values = array(); array_push($custom_fields_values, $CustomFieldsValuesInfo); $UpdateAccountCustomFieldsValuesRequest = array( 'i_account' => $this->account_info['i_account'], 'custom_fields_values' => $custom_fields_values ); $UpdateAccountCustomFieldsValuesResponse = $this->ServiceAccount->update_custom_fields_values( $UpdateAccountCustomFieldsValuesRequest ); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } $this->load_account_info(); return true; }Then we set the id of the prepaid subscription plan in the custom field values. public function set_auto_renewal( $flag ){ $text_value = 'no'; if ( $flag ) { $text_value = 'yes'; } if ( !isset( $this->account_info['CurrentSubscriptionType'] ) || $this->account_info['CurrentSubscriptionType'] == 0 ){ $this->account_info['CurrentSubscriptionType'] = 1; $this->update_subscription_plan( 1, FALSE ); } try { $CustomFieldsValuesInfo = array( 'name' => 'Auto renewal subscription plan', //'db_value' => $i_subscription_plan, 'text_value' => $text_value ); $custom_fields_values = array(); array_push($custom_fields_values, $CustomFieldsValuesInfo); $UpdateAccountCustomFieldsValuesRequest = array( 'i_account' => $this->account_info['i_account'], 'custom_fields_values' => $custom_fields_values ); $UpdateAccountCustomFieldsValuesResponse = $this->ServiceAccount->update_custom_fields_values( $UpdateAccountCustomFieldsValuesRequest ); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } return true; }Function to toggle on or off the auto-renewal in the billing database. public function set_prepaid_private_product(){ include dirname(__FILE__) . '/../etc/' . "SubscriptionPlans.php"; $i_product = 33; if ( isset( $PB_Private_Prepaid_Products[ $this->account_info['iso_4217'] ] ) ){ $i_product = $PB_Private_Prepaid_Products[ $this->account_info['iso_4217'] ]; } else { error_log("new i_product not found. using default ".$i_product ); } $AccountInfo = array( 'i_account' => $this->account_info['i_account'], 'i_product' => $i_product, ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo, ); try { $AddUpdateAccountResponse = $this->ServiceAccount->update_account($UpdateAccountRequest); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } return true; }Function for updating the product to prepaid private. private function web_db_connect(){ $filename = '/home/site_lib/connections/local.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Account_Exception( "Failed to include ". $filename ); try { $LocalMysql = new LocalMysqli; $this->LocalMysqli = $LocalMysql->connection; $this->LocalMysqli->set_charset("utf8"); return $this->LocalMysqli; } catch (mysqli_sql_exception $e) { throw new Account_Exception("Could not connect to mysql server !".$e); } }Connection to the web database. private function soap_connect(){ $filename = "credentials/soap.conf.php"; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); $filename = 'classes/PortaBillingSoapClient.php'; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); $SOAPCredentials = new SOAPCredentials; $SOAP_user = $SOAPCredentials->get_user(); $SOAP_pass = $SOAPCredentials->get_password(); if ( isset( $this->SOAP_session_id ) && $this->SOAP_session_id != '' ){ try { $this->ServiceCustomer = new PortaBillingSoapClient('', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_setSessionId( $this->SOAP_session_id ); $this->ServiceAccount = new PortaBillingSoapClient('', 'Admin', 'Account'); $this->ServiceAccount->_setSessionId( $this->SOAP_session_id ); error_log("[Account.php] USING SOAP SESSION ID : ".$this->SOAP_session_id); //print_r($this->ServiceAccount, TRUE); return $this->SOAP_session_id; } catch (SoapFault $e) { throw new Customer_Exception("Could not connect to porta-billing SOAP server !"); } } else { try { $this->ServiceCustomer = new PortaBillingSoapClient('', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_login($SOAP_user, $SOAP_pass); $this->SOAP_session_id = $session_id; $this->ServiceAccount = new PortaBillingSoapClient('', 'Admin', 'Account'); //$session_id2 = $this->ServiceAccount->_login($SOAP_user, $SOAP_pass); $this->ServiceAccount->_setSessionId( $this->SOAP_session_id ); error_log("[Account.php] NEW SOAP SESSION ID : ".$this->SOAP_session_id); return $session_id; } catch (SoapFault $e) { throw new Customer_Exception("Could not connect to porta-billing SOAP server !"); } } }Connection to SOAP. We check that we do not have a valid connection with the session id before and reuse it if it exists. private function master_db_connect(){ $filename = 'connections/master.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Account_Exception( "Failed to include ". $filename ); try { $MasterMysqli = new MasterMysqli; $this->MasterMysqli = $MasterMysqli->connection; return $this->MasterMysqli; } catch (mysqli_sql_exception $e) { throw new Account_Exception("Could not connect to mysql server !".$e); } }Connection to the master database. private function stmt_bind_assoc (&$stmt, &$out) { global $mysqli; $data = $stmt->result_metadata(); $fields = array(); $out = array(); $fields[0] = $stmt; $count = 1; while($field = $data->fetch_field()) { $fields[$count] = &$out[$field->name]; $count++; } call_user_func_array('mysqli_stmt_bind_result', $fields); }A function for saving MySQL results.}End of the account class.class Account_Exception extends Exception{ public function __construct($message = null, $code = 0, Exception $previous = null) { try { mail('nicolas.bondier@.test-google-', 'Customer management error', $message . "\n\n" . "Message sent from web server :" . __FILE__); echo "Erreur :".$message; } catch(Exception $e) { echo $e."\n"; } }}?>This class is an extension of the Exception class and send an email in case of error in try { … } catch { … } for example.Prepaid subscription surveyThis script treats the prepaid subscriptions expiration dates and renewals.[/home/site_lib/scripts/141119-prepaid-private-survey/a1.php]CodeComments<?php#$site_lib = '/home/site_lib';set_include_path( get_include_path() . PATH_SEPARATOR . $site_lib);$path = dirname(__FILE__);$LANGUAGE = 'en';require_once $path.'/languages/languages.php';require_once 'classes/PHPMailer/class.phpmailer.php';require_once 'credentials/paypal.app1.conf.php';require_once 'configurations/SubscriptionPlans.php';require_once 'configurations/products.conf.php';require_once($path.'/PPBootStrap.php');require_once 'classes/PHPMailer/class.phpmailer.php';include "configurations/currency_prices.php";Including all necessary files.$prepaid_interface_url = '';$ServiceAccount;$ServiceCustomer;$SlaveMysqli;$MasterMysqli;$LocalMysqli;Declaring the global variables that will be used later.$pid = new pid($path.'/lock');if($pid->already_running) { echo "Already running.\n"; exit;}else { echo "Running...\n";}In order to do not have multiple instances of this script running, we verify that no other instance is currently running.start();Connections to the required databases and SOAP API.$sql = 'SELECT NOW() AS mysql_datetime, DATE(NOW()) as mysql_date, CURTIME() as mysql_time, UNIX_TIMESTAMP() as unix_timestamp';$results = $SlaveMysqli->query($sql);$current_time = $results->fetch_object();First, we get the current time from the porta-billing server where are store the data.$hours_to_wake_before_midnight = 3;We set the interval in which the script must process the last charge attempt on last dayon the customer credit card or PayPal account in case of the renewal option is set.$list_to_process = array();$sql = 'SELECT a.*, p.name as product_name from Accounts a INNER JOIN Products p ON a.i_product=p.i_product WHERE p.i_product IN (33,34,35);';$stmt = $SlaveMysqli->prepare($sql);$stmt->execute();$res=array();$tmp = array();stmt_bind_assoc($stmt, $res);while ( $stmt->fetch() ){ $list_to_process[$res['i_account']] = new stdClass; $list_to_process[$res['i_account']]->account_info = ar_def($res);}$stmt->close();Getting all accounts with the prepaid private subscriptions (CHF, EUR and USD) and save the data in a hash.foreach ($list_to_process as $i_account => $account) { $sql = "SELECT * FROM Customers WHERE i_customer = ?"; $s = $stmt = $SlaveMysqli->prepare($sql) ; if ( !$s ){err($SlaveMysqli->error);} $s = $stmt->bind_param( "i", $account->account_info['i_customer'] ); if ( !$s ){err($SlaveMysqli->error);} $s = $stmt->execute(); if ( !$s ){err($SlaveMysqli->error);} stmt_bind_assoc($stmt, $res); if ( $stmt->fetch() ){ $account->customer_info = ar_def($res); } else { $account->customer_info = NULL; } $stmt->close(); if ( $account->customer_info['i_credit_card'] != NULL ){ try { $GetCustomerPaymentMethodInfoRequest = array( 'i_customer' => $account->customer_info['i_customer'] ); $GetCustomerPaymentMethodInfoResponse = $ServiceCustomer->get_payment_method_info($GetCustomerPaymentMethodInfoRequest); $account->payment_method_info = $GetCustomerPaymentMethodInfoResponse->payment_method_info; } catch (SoapFault $fault) { throw new Custom_Exception("Soap error :".$fault); return false; } } else { $account->payment_method_info = NULL; } try { $GetAccountCustomFieldsValuesRequest = array( 'i_account' => $account->account_info['i_account'] ); $GetAccountCustomFieldsValuesResponse = $ServiceAccount->get_custom_fields_values($GetAccountCustomFieldsValuesRequest); $account->custom_fields_values = $GetAccountCustomFieldsValuesResponse->custom_fields_values; } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } $account->account_info['auto_renew_subscription_plan'] = FALSE; $account->account_info['subscription_plan_id'] = 0; $account->account_info['subscription_plan_name'] = ''; foreach ($account->custom_fields_values as $custom_field) { if ( $custom_field->name == 'Prepaid subscription plan' ) { $account->account_info['subscription_plan_id'] = $custom_field->db_value; $account->account_info['subscription_plan_name'] = $custom_field->text_value; } if ( $custom_field->name == 'Auto renewal subscription plan' ) { $account->account_info['auto_renew_subscription_plan'] = $custom_field->db_value; } if ( $custom_field->name == 'Survey timestamp' ) { $account->account_info['survey_last_processed'] = $custom_field->db_value; } } if ( $account->payment_method_info->payment_method == 'PayPal' ){ $sql = "SELECT * FROM CustomerPayPalPreapprovedPayments WHERE i_customer = ?"; $stmt = $LocalMysqli->prepare($sql); $state = $stmt->bind_param( "i", $account->customer_info['i_customer'] ); $stmt->execute(); $res=array(); stmt_bind_assoc($stmt, $res); $stmt->fetch(); $stmt->close(); if ( $res['i_customer'] > 0 ){ $account->payment_method_info->senderEmail = $res['senderEmail']; if ( $res['approved'] == 1 ){ $account->payment_method_info->status = 'approved'; } else { $account->payment_method_info->status = 'pending'; } } else { $account->payment_method_info->status = 'unknown'; } }}For each of thiese accounts, we complete the data with the customer data, payment method and the option of this account like the renewal option, the free prepaid type and the last date the account was processed by this script.foreach ($list_to_process as $i_account => $account) { $LANGUAGE = strtolower( $account->customer_info['i_lang'] );All accounts data are now complete. We process accounts one by one. echo "\n######################################\n"; echo "i_account : ".$account->account_info['i_account']."\n"; echo "id : ".$account->account_info['id']."\n"; echo "survey_last_processed : ".$account->account_info['survey_last_processed']."\n"; $has_been_charged = false; $last_attempt_before_closing = false;Initiating the variables and displaying account. if ( $account->account_info['expiration_date'] != NULL ){If the expiration date is set. This is verification. Later, if it is not set we replace the product. $remove_if_no_payment = false; $last_payment_attempt_failed = true; $tomorrow = new stdClass; $tomorrow->mysql_date = date('Y-m-d', strtotime($current_time->mysql_datetime . '+1 days') ); $tomorrow->unix_timestamp = strtotime($current_time->mysql_datetime . '+1 days');We get the date for tomorrow. $day_diff = floor( ( strtotime( $account->account_info['expiration_date'] ) - strtotime( $tomorrow->mysql_date ) ) / ( 60*60*24 ) ); echo "days left : ".$day_diff." days.\n";And we calculate the remaining days before the account will be expired. if ( $day_diff == 0 ){ echo "This is the last day\n"; if ( $current_time->mysql_date == date( 'Y-m-d', strtotime( $account->account_info['survey_last_processed'] ) ) ){ echo "We have processed today\n"; $daily_time_s = date( 's' , $current_time->unix_timestamp ) + date( 'i' , $current_time->unix_timestamp ) * 60 + date( 'H' , $current_time->unix_timestamp ) * 60 * 60 ; $day_s = ( 60*60*24 ) ; $start_last_interval = $day_s - ( $hours_to_wake_before_midnight * 60 * 60 ); $processed_daily_time_s = date( 's' , strtotime($account->account_info['survey_last_processed']) ) + date( 'i' , strtotime($account->account_info['survey_last_processed']) ) * 60 + date( 'H' , strtotime($account->account_info['survey_last_processed']) ) * 60 * 60 ; /* echo '$daily_time_s :'.$daily_time_s ."\n"; echo '$day_s :'.$day_s ."\n"; echo '$start_last_interval :'.$start_last_interval ."\n"; echo '$processed_daily_time_s:'.$processed_daily_time_s."\n"; */ if ( $start_last_interval < $processed_daily_time_s && $daily_time_s > $start_last_interval ){ echo "but it was before the last period attempt\n"; $remove_if_no_payment = true; $last_payment_attempt_failed = true; } else { //echo "and it was before the last X hours before midnight\n"; continue; } } else { echo "We have processed today yet\n"; }If we are on the last day and we have processed today, we check if it was before the last interval before midnight during which we must do a last attempt. If we are before or if we are in the last interval but an attempt was made in this interval, we continue and do not attempt to charge the customer payment method. } elseif ( $day_diff > 0 ){ if ( $current_time->mysql_date == date( 'Y-m-d', strtotime( $account->account_info['survey_last_processed'] ) ) ){ echo "We have processed today\n"; continue; } else { echo $current_time->mysql_date . " =/= " . date( 'Y-m-d', strtotime( $account->account_info['survey_last_processed'] ) ) ."\n"; } } If this is not the last day, we only check if an attempt was made this day. If yes, we skip. if ( 0 <= $day_diff && $day_diff <= 2 ) { if ( $account->account_info['auto_renew_subscription_plan'] && $account->account_info['subscription_plan_id'] > 0 ){ Then we process the accounts we filtered. We check the prepaid subscription type is a valid subscription plan and that the renewal option is activated. update_renew_timestamp( $i_account, $current_time->mysql_datetime ); echo "auto renewal is set. we must process.\n";In this case, we update the timestamp in porta-billing to say that it is proceed now.$amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths'] ; $visible_comment = l('Subscription plan') . ' ' . $account->account_info['subscription_plan_name']; $internal_comment = 'Sub. plan ' . $account->account_info['subscription_plan_name'];Preparing to charge. We calculate the amount and set the comments that will be visible in the CDRs. echo "subscription plan is : ".$account->account_info['subscription_plan_name'].".\n"; echo "we will charge ".$amount." ".$account->account_info['iso_4217'].".\n";Displaying the subscription plan that will be charged and the amount and currency (which is in reality the account currency). if ( $account->payment_method_info->payment_method == 'VISA' || $account->payment_method_info->payment_method == 'MasterCard' ){In case of credit card. $transaction_result = make_credit_card_transation( $account->account_info['i_customer'], $amount, $visible_comment, $internal_comment );We make the payment with the SOAP API and we get the transaction result back. if ( $transaction_result == TRUE ){ $last_payment_attempt_failed = false; echo "credit card transaction was OK.\n"; $expiration_date = ''; $expiration_date = date( 'Y-m-d' , max( strtotime( $current_time->mysql_date ) , strtotime( $account->account_info['expiration_date'] ) ) ) ; $expiration_date = date('Y-m-d', strtotime('+'.$SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths'].' months', strtotime( $expiration_date ) ) ); echo "expiration date will be updated to ".$expiration_date.".\n"; $r = update_expiration_date( $i_account, $expiration_date ); if ( $r ){ if (!set_prepaid_private_product( $i_account, $account->account_info['iso_4217'] ) ){ err("unable to set_prepaid_private_product for i_account " . $account->account_info['i_account'] ); } else { echo "prepaid private product is set.\n"; } } else { err("unable to update_expiration_date for i_account " . $account->account_info['i_account'] ); echo "updating expiration date failed.\n"; }If the transaction was done well, we update the expiration date, set the product of the account to private prepaid. } else { err("credit card transaction failed " . $account->account_info['i_account'] ); email_automatic_payment_method_failed( $account ); echo "credit card transaction failed.\n"; }Else we send an email to the customer, informing the transaction could not be finished. } elseif ( $account->payment_method_info->payment_method == 'PayPal' ) { update_renew_timestamp( $i_account, $current_time->mysql_datetime );In case the payment method is paypal, we update the timestamp too. if ( $account->payment_method_info->status == "approved" ){And we check the authorization is approved. $transaction_result = make_paypal_transaction( $account->account_info['i_customer'], $amount, $account->account_info['iso_4217'], $visible_comment, $internal_comment );Then we make the paypal transaction. if ( $transaction_result == TRUE ){ $last_payment_attempt_failed = false; echo "credit card transaction was OK.\n"; $expiration_date = ''; $expiration_date = date( 'Y-m-d' , max( strtotime( $current_time->mysql_date ) , strtotime( $account->account_info['expiration_date'] ) ) ) ; $expiration_date = date('Y-m-d', strtotime('+'.$SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths'].' months', strtotime( $expiration_date ) ) ); echo "expiration date will be updated to ".$expiration_date.".\n"; $r = update_expiration_date( $i_account, $expiration_date ); if ( $r ){ if (!set_prepaid_private_product( $i_account, $account->account_info['iso_4217'] ) ){ err("unable to set_prepaid_private_product for i_account " . $account->account_info['i_account'] ); } else { echo "prepaid private product is set.\n"; } } else { err("unable to update_expiration_date for i_account " . $account->account_info['i_account'] ); echo "updating expiration date failed.\n"; }If the transaction was made well, we update the expiration date and set the account’s product to prepaid private. } else { err("paypal transaction failed " . $account->account_info['i_account'] ); email_automatic_payment_method_failed( $account ); echo "paypal transaction failed.\n"; }If the transaction failed, we send an email to the customer. } else { email_automatic_payment_paypal_not_approved( $account ); echo "paypal is not approved. customer must check it emails\n"; }In case the authorization is not approved, we send an email to the customer. } else { echo "no payment method and auto renewal. we will remove the auto renewal\n"; set_auto_renewal( $account->account_info['i_account'], FALSE ); }In case there was a renewal option but not set payment method, we have to remove the renewal option. } else { echo "no auto renew.\n"; update_renew_timestamp( $i_account, $current_time->mysql_datetime ); email_no_renewal_expiration_date_ends_in_X_days( $account , $day_diff ); }In case that there was no auto-renwal, we must tell that we processed this account today in the billing database and send an email to the customer inviting him to update the its subscription plan himself. } elseif ( $day_diff < 0 ) { echo "expiration is reached. we must set the product back to normal prepaid and remove subscription date.\n"; $r = remove_prepaid_private_product( $i_account, $account->account_info['iso_4217'] ); if ( $r ){ echo "private prepaid product removed.\n"; if ( remove_expiration_date( $i_account ) ){ echo "expiration date removed.\n"; email_subscription_plan_has_been_removed( $account ); } else { err("could not remove expiration date : " . $account->account_info['i_account'] ); } } else { err("could not remove prepaid private account. leave the account blocked : " . $account->account_info['i_account'] ); }This may no occurs but if we are after the expiration date, we must set back the product to normal prepaid and remove expiration date. } else { echo "expiration date is in the future and no need to renew now.\n"; }When the expiration date above the X days in which we must try to renew the account, we do nothing. } else { echo "no expiration date.\n"; remove_prepaid_private_product( $account->account_info['i_account'], $account->account_info['iso_4217'] ); }We di not find expiration date but the account is prepaid private. We must change the product back to prepaid product. if ( $last_payment_attempt_failed && $remove_if_no_payment ){ $r = remove_prepaid_private_product( $i_account, $account->account_info['iso_4217'] ); if ( $r ){ echo "private prepaid product removed.\n"; if ( remove_expiration_date( $i_account ) ){ echo "expiration date removed.\n"; } else { err("could not remove expiration date : " . $account->account_info['i_account'] ); } } else { err("could not remove prepaid private account. leave the account blocked : " . $account->account_info['i_account'] ); } }This only occurs for the last payment attempt. If it fails, we remove the expiration date and the prepaid private product.}End of the loop through accounts.stop();Closing databases connections.function make_credit_card_transation( $i_customer, $amount = 1, $visible_comment = NULL, $internal_comment = NULL ){ global $ServiceCustomer; global $ServiceAccount;# print_r( 'Credit card transaction' ); $visible_comment = substr($visible_comment, 0, 32); $internal_comment = substr($internal_comment, 0, 32); $MakeCustomerTransactionRequest = array( 'i_customer' => $i_customer, 'action' => 'e-commerce payment', 'amount' => number_format($amount,5), 'visible_comment' => $visible_comment, 'internal_comment' => $internal_comment ); try { $MakeCustomerTransactionResponse = $ServiceCustomer->make_transaction($MakeCustomerTransactionRequest); } catch (SoapFault $fault) { # throw new Custom_Exception("Soap error :".$fault); # return false; err("transaction error for i_customer ".$i_customer); } #echo "CONTINUE"; if ( !isset( $MakeCustomerTransactionResponse ) || !$MakeCustomerTransactionResponse ){ return false; } return true; #print_r($MakeCustomerTransactionResponse);}Making a transaction with credit card with SOAP API.function make_paypal_transaction( $i_customer, $amount, $currency, $visible_comment = NULL, $internal_comment = NULL ){ global $ServiceCustomer; global $ServiceAccount; global $preappouved; $conf = Configuration::getAcctAndConfig(); echo "we will make a transaction for i_customer ".$i_customer." of ".$amount." ".$currency."\n"; $actionType = "PAY"; //$returnUrl = 'http://' . $_SERVER['SERVER_NAME'] . ':' . dirname($_SERVER['PHP_SELF'])."/"; //$cancelUrl = 'http://' . $_SERVER['SERVER_NAME'] . ':' . dirname($_SERVER['PHP_SELF'])."/"; $returnUrl = ""; $cancelUrl = ""; $receiver = array(); $receiver[0] = new Receiver(); $receiver[0]->email = $conf['ReceiverEmail']; $receiver[0]->amount = $amount; $receiver[0]->primary = "false"; $receiver[0]->paymentType = "SERVICE"; $receiverList = new ReceiverList($receiver); $payRequest = new PayRequest(new RequestEnvelope("en_US"), $actionType, $cancelUrl, $currency, $receiverList, $returnUrl); $payRequest->preapprovalKey = $preappouved[$i_customer]['preapproval_key']; $payRequest->ipnNotificationUrl = $conf['IPN_URL']; $payRequest->senderEmail = $preappouved[$i_customer]['senderEmail']; $service = new AdaptivePaymentsService(Configuration::getAcctAndConfig()); try { $response = $service->Pay($payRequest); } catch(Exception $ex) { err("transaction error for i_customer ".$i_customer ); #require_once '../Common/Error.php'; } $ack = strtoupper($response->responseEnvelope->ack); if($ack != "SUCCESS") { echo "ERROR\n"; print_r($response); send_info_mail("[error] PayPal prepaid private automatic renewal", "Error during automatic payment with PayPal for i_customer $i_customer \n\n-------------\n\n". print_r($response, TRUE) ); return FALSE; } else { $payKey = $response->payKey; if(($response->paymentExecStatus == "COMPLETED" )) { send_info_mail("PayPal prepaid private automatic renewal / status: paid ", "i_customer: $i_customer \n\nDATA:\n " . print_r($response, TRUE) ); $MakeCustomerTransactionRequest = array( 'i_customer' => $i_customer, 'action' => 'Manual charge', 'amount' => sprintf('%.5f', $amount ), 'visible_comment' => $visible_comment, 'internal_comment' => $internal_comment ); try { $MakeCustomerTransactionResponse = $ServiceCustomer->make_transaction( $MakeCustomerTransactionRequest ); } catch (SoapFault $e) { err("Unable to make manual refund (for paypal payment) on i_customer ".$i_customer); } return TRUE; } else { send_info_mail("[unknown] PayPal prepaid private automatic renewal / status: unknown", "UNknown status of payment with PayPal for i_customer $i_customer \n\n-------------\n\n". print_r($response, TRUE) ); } } return FALSE;}Making a paypal transaction.function update_expiration_date( $i_account, $expiration_date = NULL ){ global $ServiceCustomer; global $ServiceAccount; $AccountInfo = array( 'i_account' => $i_account, 'expiration_date' => $expiration_date, ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo, ); try { $AddUpdateAccountResponse = $ServiceAccount->update_account($UpdateAccountRequest); } catch (SoapFault $fault) { err("Soap error :".$fault); return false; } return true;}Removing the expiration date with the SOAP API.function remove_expiration_date( $i_account ){ global $ServiceCustomer; global $ServiceAccount; $AccountInfo = array( 'i_account' => $i_account, 'expiration_date' => '', ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo, ); try { $AddUpdateAccountResponse = $ServiceAccount->update_account($UpdateAccountRequest); } catch (SoapFault $fault) { err("Soap error :".$fault); return false; } return true;}Removing the expiration date with the SOAP API.function set_auto_renewal( $i_account , $flag ){ $text_value = 'no'; if ( $flag ) { $text_value = 'yes'; } try { $CustomFieldsValuesInfo = array( 'name' => 'Auto renewal subscription plan', 'text_value' => $text_value ); $custom_fields_values = array(); array_push($custom_fields_values, $CustomFieldsValuesInfo); $UpdateAccountCustomFieldsValuesRequest = array( 'i_account' => $i_account, 'custom_fields_values' => $custom_fields_values ); $UpdateAccountCustomFieldsValuesResponse = $ServiceAccount->update_custom_fields_values($UpdateAccountCustomFieldsValuesRequest); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } return true;}Setting the auto renewal to on or of with the SOAP API.function set_prepaid_private_product( $i_account, $currency ){ global $ServiceCustomer; global $ServiceAccount; global $PB_Private_Prepaid_Products; $i_product = 33; if ( isset( $PB_Private_Prepaid_Products[ $currency ] ) ){ $i_product = $PB_Private_Prepaid_Products[ $currency ]; } else { error_log("new i_product not found. using default ".$i_product ); } $AccountInfo = array( 'i_account' => $i_account, 'i_product' => $i_product, ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo ); try { $AddUpdateAccountResponse = $ServiceAccount->update_account($UpdateAccountRequest); } catch (SoapFault $fault) { err("Soap error :".$fault); return false; } return true;}Function to set the product to prepaid private. It uses the id of the subscription plan and the general config file to subscription plans.function remove_prepaid_private_product( $i_account, $currency ){ global $ServiceCustomer; global $ServiceAccount; global $PRODUCT; $i_product = 4; if ( isset( $PRODUCT[ $currency ]['pre']['i_product'] ) ){ $i_product = $PRODUCT[ $currency ]['pre']['i_product']; } else { error_log("new i_product not found. using default ".$i_product ); } $AccountInfo = array( 'i_account' => $i_account, 'i_product' => $i_product, ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo ); try { $AddUpdateAccountResponse = $ServiceAccount->update_account($UpdateAccountRequest); } catch (SoapFault $fault) { err("Soap error :".$fault); return false; } return true;}Removing of the prepaid private product. The global variable ‘PRODUCT’ is set in the general comfiguration file for the products. It looks for the prepaid product in the corresponding currencies.function update_renew_timestamp( $i_account, $datetime ){ global $ServiceCustomer; global $ServiceAccount; echo "updating the auto renew\n"; try { $text_value = $datetime; $CustomFieldsValuesInfo = array( 'name' => 'Survey timestamp', //'db_value' => $i_subscription_plan, 'text_value' => $text_value ); $custom_fields_values = array(); array_push($custom_fields_values, $CustomFieldsValuesInfo); $UpdateAccountCustomFieldsValuesRequest = array( 'i_account' => $i_account, 'custom_fields_values' => $custom_fields_values ); $UpdateAccountCustomFieldsValuesResponse = $ServiceAccount->update_custom_fields_values($UpdateAccountCustomFieldsValuesRequest); } catch (SoapFault $fault) { throw new Account_Exception("Soap error :".$fault); return false; } return true;}This function update the custom field that represents the timestamp on which the script processed the account.function send_info_mail( $subject, $body ){ $mail_From = "prepaid_private_survey@"; $mail_Footer = "\nRegards\n\n--\n\nThis is an automatic message.\n\nhost ".php_uname('n')."\nscript ".__FILE__."\n\n\nSwitzernet ?2014 - Nicolas Bondier\n"; $mail_To = "cash@"; $mail_Header = ""; $mail_Header .= 'From: ' . $mail_From . "\r\n"; $mail_Header .= 'Reply-To: '.$mail_To . "\r\n"; $mail_Header .= 'X-Priority: 1' . "\r\n"; $mail_Header .= 'X-MSMail-Priority: High' . "\r\n"; $mail_Header .= 'Importance: High' . "\r\n"; $mail_Header .= 'Content-type: text/plain; charset=utf-8' . "\r\n"; $mail_Header .= 'X-Mailer: PHP/' . phpversion() . "\r\n"; mail($mail_To, $subject, $body, $mail_Header);}A general function to send emails.function start(){ slave_db_connect(); master_db_connect(); web_db_connect(); soap_connect();}Connection to all the databases.function stop(){ global $LocalMysqli ; global $MasterMysqli ; global $SlaveMysqli ; global $ServiceAccount ; global $ServiceCustomer; $LocalMysqli ->close(); $MasterMysqli ->close(); $SlaveMysqli ->close(); $ServiceAccount ->_logout(); $ServiceCustomer ->_logout();}Disconnect everything before closing.function slave_db_connect(){ global $SlaveMysqli; $filename = 'connections/slave.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Custom_Exception( "Failed to include ". $filename ); try { $tmp = new SlaveMysqli; $SlaveMysqli = $tmp->connection; $SlaveMysqli->set_charset("utf8"); } catch (mysqli_sql_exception $e) { throw new Custom_Exception("Could not connect to mysql server !".$e); } return $SlaveMysqli;}Connection to the slave database.function master_db_connect(){ global $MasterMysqli; $filename = 'connections/master.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Custom_Exception( "Failed to include ". $filename ); try { $tmp = new MasterMysqli; $MasterMysqli = $tmp->connection; } catch (mysqli_sql_exception $e) { throw new Custom_Exception("Could not connect to mysql server !".$e); } return $MasterMysqli;}Connection to the master database.function web_db_connect(){ global $LocalMysqli; $filename = 'connections/local.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Custom_Exception( "Failed to include ". $filename ); try { $tmp = new LocalMysqli; $LocalMysqli = $tmp->connection; $LocalMysqli->set_charset("utf8"); } catch (mysqli_sql_exception $e) { throw new Custom_Exception("Could not connect to mysql server !".$e); } return $LocalMysqli;}Connection to the web database.function soap_connect(){ global $ServiceCustomer; global $ServiceAccount; $filename = "credentials/soap.conf.php"; if(!@include_once( $filename ) ) throw new Custom_Exception( "Failed to include ". $filename ); $filename = 'classes/PortaBillingSoapClient.php'; if(!@include_once( $filename ) ) throw new Custom_Exception( "Failed to include ". $filename ); $SOAPCredentials = new SOAPCredentials; $SOAP_user = $SOAPCredentials->get_user(); $SOAP_pass = $SOAPCredentials->get_password(); try { $ServiceCustomer = new PortaBillingSoapClient('', 'Admin', 'Customer'); $session_id = $ServiceCustomer->_login($SOAP_user, $SOAP_pass); $ServiceAccount = new PortaBillingSoapClient('', 'Admin', 'Account'); $ServiceAccount->_setSessionId($session_id); } catch (SoapFault $e) { throw new Custom_Exception("Could not connect to porta-billing SOAP server !"); } return $session_id;}Connection to SOAP API.function stmt_bind_assoc (&$stmt, &$out) { $data = $stmt->result_metadata(); $fields = array(); $out = array(); $fields[0] = $stmt; $count = 1; while($field = $data->fetch_field()) { $fields[$count] = &$out[$field->name]; $count++; } call_user_func_array('mysqli_stmt_bind_result', $fields);}Function to retrieve results of a MySQL query with prepaid statements. It return the data in a hash.function err( $message , $mail = TRUE ){ try { mail('nicolas.bondier@','prepay private survey error', $message . "\n\n" . "Message sent from web server script:" . __FILE__); echo $message."\n"; } catch(Exception $e) { echo $e."\n"; }}An error function that send emails.class Custom_Exception extends Exception{ public function __construct($message = null, $code = 0, Exception $previous = null) { $this->err( $message , $mail = TRUE ); } function err( $message , $mail = TRUE ){ try { mail('nicolas.bondier@','prepay private survey error', $message . "\n\n" . "Message sent from web server script:" . __FILE__); echo $message."\n"; } catch(Exception $e) { echo $e."\n"; } }}# emails : An extension of the extension class that send emails. It is useful for SOAP request for example.function email_automatic_payment_method_failed ( $account ){ #print_r($account); global $current_time; global $SubscriptionPlans; global $prepaid_interface_management_url; include "configurations/currency_prices.php"; $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths']; $subject = ''; $body = ''; $subject .= l('The automatic paiment for the renewal of your subscription failed'); $body .= '<p>'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",</p>"; $body .= '<p>'.l('On').' ' . $current_time->mysql_datetime .', '; $body .= l('the automatic payment of'). ' ' . number_format( $amount , 2 ) . ' ' . $account->account_info['iso_4217'] . ' ' . l('for the renewal of the subscription that you choosed for your VoIP account ') . $account->account_info['id'].' '.l('failed.') . '</p>'; $body .= '<p>'.l('In order to continue to benefit of your prepaid subscription, thank you to update your automatic payment information in your').' <a href="'.$prepaid_interface_management_url.'">'.l('prepaid subscription management web interface'). '</a> ' . l('and also to verify that your credit card/paypal account have available funds to process the payment.').'</p>'; $body .= '<p>'.l('We would remind you that your actual subscription, which includes free calls to many countries and advantaging rates to numerous other destinations, will end up on ') . date('Y-m-d', strtotime($account->account_info['expiration_date'] . ' -1 days' )) . ' ' . l('if it is not renewed.'); $body .= ' ' . l('Calls made with your account ') . $account->account_info['id'] . ' ' . l("will be charged with the 'prepaid' rates (no free destination, calls at "). $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] .l("/min minimum, connection fees at ") . $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] . ').<p>'; $body .= '<p>'.l('Best regards').',<br>'; $body .= l('Switzernet team').'</p>'; # . number_format( $amount , 2 ) . ' ' . $account->account_info['iso_4217'] . ' ' . l('for the renewal of the subscription that you choosed for your VoIP account ') . $account->account_info['id'].' '.l('failed.'); send_email_to_customer( $account->customer_info['email'], $subject, $body );}The email sent to customer informing that its automatic payment failed.function email_automatic_payment_paypal_not_approved ( $account ){ global $current_time; global $SubscriptionPlans; global $prepaid_interface_management_url; include "configurations/currency_prices.php"; $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths']; $subject = ''; $body = ''; $subject .= l('The automatic paiment for the renewal of your subscription failed'); $body .= '<p>'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",</p>"; $body .= '<p>'.l('On').' ' . $current_time->mysql_datetime .', '; $body .= l('the automatic payment of'). ' ' . number_format( $amount , 2 ) . ' ' . $account->account_info['iso_4217'] . ' ' . l('for the renewal of the subscription that you choosed for your VoIP account ') . $account->account_info['id'].' '.l('could not be processed you did not approved the PayPal authorization.') . '</p>'; $body .= '<p>'.l('In order to continue to benefit of your prepaid subscription, thank you to approve the PayPal authorization in your').' <a href="'.$prepaid_interface_management_url.'">'.l('prepaid subscription management web interface'). '</a> ' . l('and also to verify that your paypal account have available funds to process the payment.').'</p>'; $body .= '<p>'.l('We would remind you that your actual subscription, which includes free calls to many countries and advantaging rates to numerous other destinations, will end up on ') . date('Y-m-d', strtotime($account->account_info['expiration_date'] . ' -1 days' )) . ' ' . l('if it is not renewed.'); $body .= ' ' . l('Calls made with your account ') . $account->account_info['id'] . ' ' . l("will be charged with the 'prepaid' rates (no free destination, calls at "). $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] .l("/min minimum, connection fees at ") . $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] . ').<p>'; $body .= '<p>'.l('Best regards').',<br>'; $body .= l('Switzernet team').'</p>'; send_email_to_customer( $account->customer_info['email'], $subject, $body );}An email to the customer informaing that the PayPal account authorization is not approved.function email_no_renewal_expiration_date_ends_in_X_days( $account, $number_of_days ){ global $current_time; global $SubscriptionPlans; global $prepaid_interface_management_url; include "configurations/currency_prices.php"; $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths']; $subject = ''; $body = ''; $subject .= l('Your subscription for your VoIP account') . ' ' . $account->account_info['id'] . ' ' . l('will expire soon.'); $body .= '<p>'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",</p>"; $body .= '<p>'.l('We would like to inform you that the subscription you choosed for your VoIP account') . ' ' . $account->account_info['id'] . ' ' . l('will expire in') . ' ' . $number_of_days . ( $number_of_days > 1 ? l('days') : l('day') ) . '.</p>' ; $body .= '<p>'.l('In order to continue to benefit its advantages, thank you to renew it from your').' <a href="'.$prepaid_interface_management_url.'">' . l('prepaid subscription management web interface') . '</a></p>'; $body .= '<p>'.l('Your actual subscription, which includes free calls to many countries and advantaging rates to numerous other destinations, will end up on') . ' ' . date('Y-m-d', strtotime($account->account_info['expiration_date'] . ' -1 days' )) . ' ' . l('if it is not renewed.'); $body .= ' ' . l('Calls made with your account') . ' ' . $account->account_info['id'] . ' ' . l("will be charged with the 'prepaid' rates (no free destination, calls at")." ". $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] .l("/min minimum, connection fees at") . ' ' . $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] . ').<p>'; $body .= '<p>'.l('Best regards').',<br>'; $body .= l('Switzernet team').'</p>'; send_email_to_customer( $account->customer_info['email'], $subject, $body );}This email is sent when the customer has no renewal option activated or no credit card set. It informs the customer in how many days the subscription plan expires.function email_subscription_plan_has_been_removed( $account ){ global $PRICES; $subject = ''; $subject .= l('Your subscription for your VoIP account') . ' ' . $account->account_info['id'] . ' ' . l('has expired.'); $body = ''; $body .= '<p>'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",</p>"; $body .= '<p>'.l('We would like to inform you that the subscription you choosed for your VoIP account') . ' ' . $account->account_info['id'] . ' ' . l('has expired.'); $body .= '<p>' . l('Calls made with your account') . ' ' . $account->account_info['id'] . ' ' . l("will be charged with the 'prepaid' rates (no free destination, calls at")." ". $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] .l("/min minimum, connection fees at") . ' ' . $PRICES[$account->account_info['iso_4217']]['RATE_PREPAID_MINIMUM'] . " " . $account->account_info['iso_4217'] . ').<p>'; send_email_to_customer( $account->customer_info['email'], $subject, $body );}The email informing that the subscription plan has been removed and the product has changed.function send_email_to_customer( $email, $subject, $body ){ if (filter_var($email, FILTER_VALIDATE_EMAIL)) { $mail = new PHPMailer; $mail->CharSet = 'UTF-8'; $mail->From = 'billing@'; $mail->FromName = 'Switzernet'; $mail->addAddress( $email ); // Add a recipient $mail->addAddress( 'billing@' ); // Add a recipient $mail->AddReplyTo( 'billing@' , 'Billing'); $mail->Subject = $subject; $mail->Body = $body; $mail->IsHTML(); return $mail->send(); } else { return false; }}General function to send the email to customer.class pid { protected $filename; public $already_running = false; function __construct($directory) { $this->filename = $directory . '/' . basename($_SERVER['PHP_SELF']) . '.pid'; if(is_writable($this->filename) || is_writable($directory)) { if(file_exists($this->filename)) { $pid = (int)trim(file_get_contents($this->filename)); if(posix_kill($pid, 0)) { $this->already_running = true; } } } else { die("Cannot write to pid file '$this->filename'. Program execution halted.\n"); } if(!$this->already_running) { $pid = getmypid(); file_put_contents($this->filename, $pid); } } public function __destruct() { if(!$this->already_running && file_exists($this->filename) && is_writeable($this->filename)) { unlink($this->filename); } }}This class manage the running process and permit to check if anyone is running in the same tim.?>* * *Copyright ? DATE \@ "yyyy" 2014 by Switzernet ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download