Private Prepaid Subscriptions

Total Page:16

File Type:pdf, Size:1020Kb

Private Prepaid Subscriptions

[1'e99'1 subscriptions]

Private prepaid subscription interface and survey script

Document created on 2014-11-24 Nicolas Bondier

Contents

Introduction

This document describes the prepaid subscription web interface and the scripts used to manage prepaid private subscriptions.

Web interface

The 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.

Page 1/65 Page 2/65 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

Page 3/65 │ └── 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

Page 4/65 │ ├── 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.php

All sources

Initialization scripts The 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

Page 5/65 [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.

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/d ocument/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.

require_once dirname(__FILE__) . "/" . 'init_common.php';

Page 6/65 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 [link] '; 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.

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.

if ( isset( $_SESSION[AppId]['AUTHENTICATED'] ) && $_SESSION[AppId] ['AUTHENTICATED'] === TRUE ){

Page 8/65 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.

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.

Page 9/65 Here is the code:

[index.php]

Page 10/65 $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"); } } } ?> Switzernet

".$error.""; } ?>

Page 11/65

Backend

The following scripts are used to get information about customer and account and modify them.

Customer class [classes/Customer.php]

Code Comment

/** * */

Declaring public class Customer { properties. public $customer_info; public $update_flag; public $porta_billing_customer = FALSE; public $web_subscription = FALSE;

Page 12/65 Declaring private private $LocalMysqli; properties. private $MasterMysqli; private $ServiceCustomer; private $ServiceAccount; private $SOAP_session_id = '';

Constructors and function __construct() { destructors. They are $this->web_db_connect(); called when the class is

$this->master_db_connect(); loaded or closed or

$this->soap_connect(); serialized. } function __destruct(){ $this->LocalMysqli->close(); $this->MasterMysqli->close(); } function __wakeup(){ $this->soap_connect(); $this->web_db_connect(); $this->master_db_connect(); }

This function is used to public function load_customer_info( $check_update = FALSE ){ 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.

In order to tell if info $old_customer_info = $this->customer_info; has been updated we first get the current customer info.

Page 13/65 If the customer is if ( $this->porta_billing_customer === FALSE && $this- marked as not yet in >web_subscription === TRUE ){ the porta-billing, we $sql = "SELECT active_in_porta_billing, pb_i_customer FROM Web_Subscriptions WHERE i_web_subscription = ?"; check if it is still true. $stmt = $this->LocalMysqli->prepare($sql); $state = $stmt->bind_param( "i", $this- In this case we update >customer_info['i_web_subscription'] ); the web subscription $stmt->execute(); database and set the $res=array(); porta_billing_customer $this->stmt_bind_assoc($stmt, $res); flag to ‘true’ in order $stmt->fetch(); to process as a $stmt->close(); portabilling customer. 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 in if ( $this->porta_billing_customer ){ the porta-billing $sql = "SELECT c.*, a.id, a.i_account FROM Customers c INNER JOIN database, we select all Accounts a ON a.i_customer=c.i_customer WHERE c.i_customer = ? AND a.bill_status = 'O'"; its data. $stmt = $this->MasterMysqli->prepare($sql); $state = $stmt->bind_param( "i", $this- >customer_info['i_customer'] ); $stmt->execute(); $res=array();

Page 14/65 $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; }

And we also set the $this->customer_info['Active'] = TRUE; values used by the web $this->customer_info['Email'] = $this- interface. >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'];

Getting the payment $this->get_payment_method(); method.

Page 15/65 } elseif ( $this->web_subscription === TRUE ) { In case it is a web subscription, we get $sql = "SELECT * FROM Web_Subscriptions WHERE i_web_subscription the data from the = ?"; database and set the $stmt = $this->LocalMysqli->prepare($sql); values used by the web $state = $stmt->bind_param( "i", $this- >customer_info['i_web_subscription'] ); interface. $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; }

We calculate the $this->customer_info['AvailableFunds'] = max( ( $this- available funds of the >customer_info['CreditLimit'] - $this->customer_info['Balance'] ), 0 ); customer. $this->customer_info['AvailableFunds'] = ( $this- >customer_info['CreditLimit'] - $this->customer_info['Balance'] );

Get the list of $this->get_customer_prepaid_accounts(); accounts. This is for verifying if it changed in the database since the last update. If the $check_update $new_customer_info = $this->customer_info;

Page 16/65 if ( $check_update == TRUE && $new_customer_info != variable is true, with $old_customer_info ){ check the customer $this->update_flag = TRUE; has been update since

} else { the last update. $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;

Ending of the } load_customer_info() function. This function public function authenticate( $user, $password ){ authenticate the //print_r($this); customer with its

$sql = "SELECT i_customer FROM Customers WHERE login = ? AND username and password = ?"; //echo $sql; password. $stmt = $this->MasterMysqli->prepare($sql); It first check in the /* Prepared statement, stage 1: prepare */ billing database the $state = $stmt->bind_param( "ss", $user, $password ); username and $stmt->execute(); password pair exists, $res=array(); else it checks in the $this->stmt_bind_assoc($stmt, $res); web subscriptions $stmt->fetch(); database. $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();

Page 17/65 $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 is used to public function set_customer ($i_customer){ set the i_customer of //print_r($this); the current object if it

$sql = "SELECT i_customer FROM Customers WHERE i_customer = ?"; exists. //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 public function charge( $amount, $visible_comment = 'order', charge the balance of $internal_comment = 'prepaid interface order' ){ the customer. $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 {

Page 18/65 $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 save the public function update_payment_method( $payment_method_data ){ payment method to the porta-billing. Validating the available $pm = $payment_method_data['AutomaticPaymentMethod']; payment methods.

$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; }

First we check all if ( $pm == 'VISA' || $pm == 'MasterCard' ){ necessary fields is this is a credit card. 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'),

Page 19/65 ); 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'),

Page 20/65 ); return $return; }

Setting default card values for other fields. $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'; }

And finaly we save the data whith SOAP XML $PaymentMethodInfo = array( API. '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'] );

Page 21/65 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 } elseif ( $pm == 'PayPal' ) { method is PayPal we only update the $PaymentMethodInfo = array( master database with 'payment_method' => 'PayPal' SOAP. );

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; }

Finally, if the customer } else { did not choose any of the payment method, $PaymentMethodInfo = array( we delete all renewal 'payment_method' => NULL ); options of the try { accounts. $UpdateCustomerPaymentMethodRequest = $this->ServiceCustomer-

Page 22/65 >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; } } }

The function used for private function remove_all_accounts_renewal_options(){ removing all renewal file_put_contents('/tmp/AccountsList.txt', print_r( $this- options of all account. >customer_info['AccountsList'] , true ) ); Generally this is when foreach ( $this->customer_info['AccountsList'] as $i_account => $number) { the customer does not try { have payment method. $CustomFieldsValuesInfo = array( The values are in the 'name' => 'Auto renewal subscription plan', custom fields values of //'db_value' => $i_subscription_plan, the database. '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; }

Here we get the

Page 23/65 private function get_payment_method(){ information about the if ( $this->customer_info['i_credit_card'] != NULL && $this- payment method of >customer_info['i_credit_card'] > 0 ){ the user. $cols = array();

$cols_array = array(); In order to limit credit $sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE card transfer, we check table_name = 'Credit_Cards'"; if we have the same if (!($stmt = $this->MasterMysqli->prepare($sql))) { data has in billing data- echo "Echec de la préparation : (" . $MasterMysqli->errno . ") base. " . $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'] ){

If this is the case, we $this->customer_info['credit_card_hash'] = get the credit card $res['credit_card_hash']; number and the $GetCustomerPaymentMethodInfoRequest = array( 'i_customer' => $this->customer_info['i_customer'] ); payment method.

Page 24/65 $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 PayPal, we if ( $this->customer_info['AutomaticPaymentMethod'] == 'PayPal' ) must also verify the { status of the $sql = "SELECT * FROM CustomerPayPalPreapprovedPayments WHERE i_customer = ?"; authorization in order $stmt = $this->LocalMysqli->prepare($sql); to display to the $state = $stmt->bind_param( "i", $this- customer. >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'; } } } }

Page 25/65 This function return public function get_customer_prepaid_accounts(){ the list of prepaid accounts the customer $accounts = array(); has or the list of if ( $this->porta_billing_customer ){ ordered accounts if the $sql = 'SELECT a.i_account, a.id as ID FROM Accounts a INNER JOIN customer is not yet in Products p ON a.i_product = p.i_product WHERE a.i_customer = ? AND the billing database. 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

Page 26/65 public function get_customer_accounts(){ the list of accounts the customer has or the $accounts = array(); list of ordered

if ( $this->porta_billing_customer ){ accounts if the

$sql = 'SELECT a.i_account, a.id as ID FROM Accounts a WHERE customer is not yet in a.i_customer = ? AND a.bill_status = "O"'; if (!($stmt = $this->MasterMysqli->prepare($sql))) { the billing database. echo "Echec de la préparation : (" . $MasterMysqli->errno . ") " . $LocalMysqli->error; This is not used for the } moment as we only $state = $stmt->bind_param( "i", $this- display the prepaid >customer_info['i_customer'] ); accounts. $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; } }

Connection to the web private function web_db_connect(){ database. $filename = '/home/site_lib/connections/local.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename );

Page 27/65 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 private function master_db_connect(){ master database. $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 SOAP. 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('https://slave.switzernet.com:8444', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_setSessionId( $this- >SOAP_session_id );

Page 28/65 $this->ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', '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('https://slave.switzernet.com:8444', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_login($SOAP_user, $SOAP_pass); $this->SOAP_session_id = $session_id; $this->ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', '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 !"); } } }

A function for saving private function stmt_bind_assoc (&$stmt, &$out) { MySQL results. 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);

Page 29/65 }

Function to call for public function _close(){ closing the object. $this->LocalMysqli->close(); $this->MasterMysqli->close(); } }

This class is an class Customer_Exception extends Exception{ extension of the public function __construct($message = null, $code = 0, Exception $previous = null) { Exception class and try { send an email in case mail('[email protected]', of error in try { … } 'Customer management error', catch { … } for $message . "\n\n" . "Message sent from web server :" . example. __FILE__); echo "Erreur :".$message; } catch(Exception $e) { echo $e."\n"; } } }

?>

Account class [classes/Account.php]

Code Comments

Public public $account_info; properties. public $porta_billing_account = FALSE;

Private private $LocalMysqli; properties. private $MasterMysqli; private $ServiceCustomer;

Page 30/65 private $ServiceAccount;

Constructors function __construct() { and destructors. $this->web_db_connect(); They are called

$this->master_db_connect(); when the class

$this->soap_connect(); is loaded or } closed or function __wakeup(){ serialized. $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(); }

Function for public function load_account_info(){ getting the account info. In case the if ( $this->porta_billing_account == TRUE ){ account is a $param = ''; porta-billing

if ( isset( $this->account_info['ID'] ) ){ account, we get

$param = $this->account_info['ID']; the list from it. $sql = "SELECT *,NOW() as CurrentTime FROM Accounts WHERE id = ?"; We check $stmt = $this->MasterMysqli->prepare($sql); before which $state = $stmt->bind_param( "s", $param ); element we $stmt->execute(); $res=array(); have, the $this->stmt_bind_assoc($stmt, $res); i_account or ID. $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'] ) ){

Page 31/65 $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; } }

We set the $this->account_info['CurrentSubscriptionType'] = 0; default variable $this->account_info['CurrentSubscriptionExpirationDate'] = '0000-00-00 for the 00:00:00'; subscription $this->account_info['SubscriptionAutoRenewal'] = '0'; type, expiration $this->account_info['IsPrepaidPrivate'] = false; $this->get_subscription_plan(); date and the $this->account_info['Active'] = 1; get_subscription plan get the current values. If the customer } else { is not yet in the billing. We select the $param = ''; values from the if ( isset( $this->account_info['ID'] ) ){ web

$param = $this->account_info['ID']; subscription

$sql = "SELECT *, NOW() as CurrentTime FROM database and Web_Subscription_Selected_Numbers WHERE h323_id = ?"; $stmt = $this->LocalMysqli->prepare($sql); set the info $state = $stmt->bind_param( "s", $param ); about $stmt->execute(); subscription to $res=array(); defaults values. $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';

Page 32/65 $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; }

} 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; } }

End of loading } account. return TRUE; }

Function for public function set_i_account($i_account){ setting $this->account_info['i_account'] = $i_account; i_account to the

} object. Function for public function set_account_id($id){ setting id to the $this->account_info['ID'] = $id; object.

Page 33/65 }

Function for public function get_subscription_plan(){ getting include dirname(__FILE__) . '/../etc/' . "SubscriptionPlans.php"; subscription plans. We include the file containing the information for each subscription plan. We look to the if ( isset( $PB_Private_Prepaid_Products[ $this->account_info['iso_4217'] ] ) products of the && $this->account_info['i_product'] == $PB_Private_Prepaid_Products[ $this- >account_info['iso_4217'] ] ){ customer to see $this->account_info['IsPrepaidPrivate'] = true; if it is prepaid } else { private. $this->account_info['IsPrepaidPrivate'] = false; }

As well as the if ( isset( $this->account_info['expiration_date'] ) && $this- expiration date. >account_info['expiration_date'] != '' ){ $this->account_info['CurrentSubscriptionExpirationDate'] = $this- >account_info['expiration_date']; } else { $this->account_info['CurrentSubscriptionExpirationDate'] = NULL; }

And we get the try { custom fields $GetAccountCustomFieldsValuesRequest = array( values to get the 'i_account' => $this->account_info['i_account'] subscription ); auto renewal

$GetAccountCustomFieldsValuesResponse = $this->ServiceAccount- state and the >get_custom_fields_values($GetAccountCustomFieldsValuesRequest); type of //error_log(print_r($GetAccountCustomFieldsValuesResponse, TRUE)); } catch (SoapFault $fault) { subscription. 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-

Page 34/65 >db_value; } if ( $custom_fields_value->name == 'Prepaid subscription plan' ){ $this->account_info['CurrentSubscriptionType'] = $custom_fields_value- >db_value; } } }

Function for public function update_subscription_plan( $i_subscription_plan, updating the $update_expiration_date = TRUE ){ subscription plan. First we check if include dirname(__FILE__) . '/../etc/' . "SubscriptionPlans.php"; we need to if ( !isset( $SubscriptionPlans[$i_subscription_plan] ) ){ update the

return FALSE; expiration date

} and process. 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' ) ),

Page 35/65 ); $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; } } } }

Then we set the try { id of the prepaid $text_value = 'no subscription plan'; subscription

if ( $i_subscription_plan == 1 ){ plan in the

$text_value = '1 month'; custom field } elseif ( $i_subscription_plan > 1 ){ values. $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; }

Page 36/65 Function to public function set_auto_renewal( $flag ){ toggle on or off $text_value = 'no'; the auto-

if ( $flag ) { renewal in the

$text_value = 'yes'; billing database. } 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; }

public function set_prepaid_private_product(){ Function for include dirname(__FILE__) . '/../etc/' . "SubscriptionPlans.php"; updating the product to $i_product = 33; prepaid private. 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(

Page 37/65 '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; }

Connection to private function web_db_connect(){ the web $filename = '/home/site_lib/connections/local.mysqli.class.php'; database. 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 private function soap_connect(){ SOAP. We check that we do not $filename = "credentials/soap.conf.php"; have a valid if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to include ". $filename ); connection with the session id $filename = 'classes/PortaBillingSoapClient.php'; before and if(!@include_once( $filename ) ) throw new Customer_Exception( "Failed to reuse it if it include ". $filename ); exists. $SOAPCredentials = new SOAPCredentials; $SOAP_user = $SOAPCredentials->get_user(); $SOAP_pass = $SOAPCredentials->get_password();

if ( isset( $this->SOAP_session_id ) && $this->SOAP_session_id != '' ){

Page 38/65 try { $this->ServiceCustomer = new PortaBillingSoapClient('https://slave.switzernet.com:8444', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_setSessionId( $this- >SOAP_session_id ); $this->ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', '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('https://slave.switzernet.com:8444', 'Admin', 'Customer'); $session_id = $this->ServiceCustomer->_login($SOAP_user, $SOAP_pass); $this->SOAP_session_id = $session_id; $this->ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', '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 private function master_db_connect(){ the master $filename = 'connections/master.mysqli.class.php'; database. if(!@include_once( $filename ) ) throw new Account_Exception( "Failed to include ". $filename ); try { $MasterMysqli = new MasterMysqli; $this->MasterMysqli = $MasterMysqli->connection; return $this->MasterMysqli;

Page 39/65 } catch (mysqli_sql_exception $e) { throw new Account_Exception("Could not connect to mysql server !".$e); } }

A function for private function stmt_bind_assoc (&$stmt, &$out) { saving MySQL global $mysqli; results. $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); }

End of the } account class. This class is an class Account_Exception extends Exception{ extension of the public function __construct($message = null, $code = 0, Exception $previous = null) { Exception class try { and send an mail('[email protected]', email in case of 'Customer management error', error in try { … } $message . "\n\n" . "Message sent from web server :" . __FILE__); catch { … } for echo "Erreur :".$message; example. } catch(Exception $e) { echo $e."\n"; } } }

?>

Prepaid subscription survey

This script treats the prepaid subscriptions expiration dates and renewals.

Page 40/65 [/home/site_lib/scripts/141119-prepaid-private-survey/a1.php]

Code Comments

$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";

Declaring the $prepaid_interface_url = 'http://switzernet.com/3/company/141029-prepaid- subscription-web-interface/'; global variables that $ServiceAccount; will be used $ServiceCustomer; later. $SlaveMysqli; $MasterMysqli; $LocalMysqli;

In order to do $pid = new pid($path.'/lock'); if($pid->already_running) { not have echo "Already running.\n"; multiple exit; instances of } this script else { running, we echo "Running...\n"; verify that no } other instance is currently running. Connections start(); to the required databases and SOAP API. First, we get $sql = 'SELECT NOW() AS mysql_datetime, DATE(NOW()) as mysql_date, CURTIME() as

Page 41/65 mysql_time, UNIX_TIMESTAMP() as unix_timestamp'; the current $results = $SlaveMysqli->query($sql); time from the porta-billing $current_time = $results->fetch_object(); server where are store the data. We set the $hours_to_wake_before_midnight = 3; 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. Getting all $list_to_process = array(); $sql = 'SELECT a.*, p.name as product_name from Accounts a INNER JOIN Products p ON accounts with a.i_product=p.i_product WHERE p.i_product IN (33,34,35);'; the prepaid $stmt = $SlaveMysqli->prepare($sql); private $stmt->execute(); subscriptions $res=array(); $tmp = array(); (CHF, EUR and stmt_bind_assoc($stmt, $res); USD) and save the data in a while ( $stmt->fetch() ){ hash. $list_to_process[$res['i_account']] = new stdClass; $list_to_process[$res['i_account']]->account_info = ar_def($res); } $stmt->close();

For each of foreach ($list_to_process as $i_account => $account) { thiese $sql = "SELECT * FROM Customers WHERE i_customer = ?"; accounts, we $s = $stmt = $SlaveMysqli->prepare($sql) ; complete the if ( !$s ){err($SlaveMysqli->error);} data with the $s = $stmt->bind_param( "i", $account->account_info['i_customer'] ); customer if ( !$s ){err($SlaveMysqli->error);} data, $s = $stmt->execute(); payment if ( !$s ){err($SlaveMysqli->error);} method and stmt_bind_assoc($stmt, $res); the option of

Page 42/65 if ( $stmt->fetch() ){ this account $account->customer_info = ar_def($res); like the } else { renewal $account->customer_info = NULL; option, the } free prepaid $stmt->close(); type and the if ( $account->customer_info['i_credit_card'] != NULL ){ last date the

try { account was $GetCustomerPaymentMethodInfoRequest = array( 'i_customer' => $account- >customer_info['i_customer'] ); processed by $GetCustomerPaymentMethodInfoResponse = $ServiceCustomer- this script. >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' ) {

Page 43/65 $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'; } } }

All accounts foreach ($list_to_process as $i_account => $account) { data are now $LANGUAGE = strtolower( $account->customer_info['i_lang'] ); complete. We process accounts one by one.

Initiating the echo "\n######################################\n"; variables and displaying echo "i_account : ".$account->account_info['i_account']."\n"; account. 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;

If the if ( $account->account_info['expiration_date'] != NULL ){ expiration date is set.

Page 44/65 This is verification. Later, if it is not set we replace the product. We get the $remove_if_no_payment = false; date for $last_payment_attempt_failed = true; tomorrow.

$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');

And we $day_diff = floor( ( strtotime( $account->account_info['expiration_date'] ) - calculate the strtotime( $tomorrow->mysql_date ) ) / ( 60*60*24 ) ); remaining echo "days left : ".$day_diff." days.\n"; days before the account will be expired. If we are on if ( $day_diff == 0 ){ the last day echo "This is the last day\n"; and we have

if ( $current_time->mysql_date == date( 'Y-m-d', strtotime( $account- processed >account_info['survey_last_processed'] ) ) ){ today, we echo "We have processed today\n"; $daily_time_s = date( 's' , $current_time->unix_timestamp ) + date( check if it was 'i' , $current_time->unix_timestamp ) * 60 + date( 'H' , $current_time- before the >unix_timestamp ) * 60 * 60 ; last interval $day_s = ( 60*60*24 ) ; before $start_last_interval = $day_s - ( $hours_to_wake_before_midnight * 60 * 60 midnight ); during which $processed_daily_time_s = date( 's' , strtotime($account- >account_info['survey_last_processed']) ) + date( 'i' , strtotime($account- we must do a >account_info['survey_last_processed']) ) * 60 + date( 'H' , strtotime($account- last attempt. >account_info['survey_last_processed']) ) * 60 * 60 ; If we are before or if /* we are in the echo '$daily_time_s :'.$daily_time_s ."\n"; last interval echo '$day_s :'.$day_s ."\n"; but an echo '$start_last_interval :'.$start_last_interval ."\n"; echo '$processed_daily_time_s:'.$processed_daily_time_s."\n"; attempt was */ made in this interval, we if ( $start_last_interval < $processed_daily_time_s && $daily_time_s > continue and

Page 45/65 $start_last_interval ){ do not echo "but it was before the last period attempt\n"; attempt to $remove_if_no_payment = true; charge the

$last_payment_attempt_failed = true; customer

} else { payment //echo "and it was before the last X hours before midnight\n"; method. continue; } } else { echo "We have processed today yet\n"; }

If this is not } elseif ( $day_diff > 0 ){ the last day, if ( $current_time->mysql_date == date( 'Y-m-d', strtotime( $account- we only check >account_info['survey_last_processed'] ) ) ){ if an attempt echo "We have processed today\n"; was made this continue; } else { day. If yes, we echo $current_time->mysql_date . " =/= " . date( 'Y-m-d', strtotime( skip. $account->account_info['survey_last_processed'] ) ) ."\n"; } }

Then we if ( 0 <= $day_diff && $day_diff <= 2 ) { process the if ( $account->account_info['auto_renew_subscription_plan'] && $account- accounts we >account_info['subscription_plan_id'] > 0 ){ filtered. We check the prepaid subscription type is a valid subscription plan and that the renewal option is activated. In this case, update_renew_timestamp( $i_account, $current_time->mysql_datetime ); we update echo "auto renewal is set. we must process.\n"; the timestamp in porta-billing to say that it is proceed now. Preparing to

Page 46/65 $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ charge. We 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths'] ; calculate the $visible_comment = l('Subscription plan') . ' ' . $account- amount and >account_info['subscription_plan_name']; set the $internal_comment = 'Sub. plan ' . $account- comments >account_info['subscription_plan_name']; that will be visible in the CDRs.

Displaying the echo "subscription plan is : ".$account- subscription >account_info['subscription_plan_name'].".\n"; plan that will echo "we will charge ".$amount." ".$account->account_info['iso_4217'].".\n"; be charged and the amount and currency (which is in reality the account currency). In case of if ( $account->payment_method_info->payment_method == 'VISA' || $account- credit card. >payment_method_info->payment_method == 'MasterCard' ){

We make the $transaction_result = make_credit_card_transation( payment with $account->account_info['i_customer'], the SOAP API

$amount, and we get

$visible_comment, the $internal_comment transaction ); result back. If the if ( $transaction_result == TRUE ){ transaction $last_payment_attempt_failed = false; was done

echo "credit card transaction was OK.\n"; well, we

$expiration_date = ''; update the $expiration_date = date( 'Y-m-d' , max( strtotime( $current_time- >mysql_date ) , strtotime( $account->account_info['expiration_date'] ) ) ) ; expiration $expiration_date = date('Y-m-d', strtotime('+'.$SubscriptionPlans[ date, set the $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths'].' months', product of the strtotime( $expiration_date ) ) ); account to echo "expiration date will be updated to ".$expiration_date.".\n"; private $r = update_expiration_date( $i_account, $expiration_date ); prepaid. if ( $r ){ if (!set_prepaid_private_product( $i_account, $account- >account_info['iso_4217'] ) ){

Page 47/65 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"; }

Else we send } else { an email to err("credit card transaction failed " . $account- the customer, >account_info['i_account'] ); informing the email_automatic_payment_method_failed( $account ); echo "credit card transaction failed.\n"; transaction } could not be finished. In case the } elseif ( $account->payment_method_info->payment_method == 'PayPal' ) { payment update_renew_timestamp( $i_account, $current_time->mysql_datetime ); method is paypal, we update the timestamp too.

And we check if ( $account->payment_method_info->status == "approved" ){ the authorization is approved. Then we $transaction_result = make_paypal_transaction( make the $account->account_info['i_customer'], paypal

$amount, transaction. $account->account_info['iso_4217'], $visible_comment, $internal_comment );

If the if ( $transaction_result == TRUE ){ transaction was made $last_payment_attempt_failed = false; well, we echo "credit card transaction was OK.\n"; update the $expiration_date = ''; $expiration_date = date( 'Y-m-d' , max( strtotime( $current_time- expiration

Page 48/65 >mysql_date ) , strtotime( $account->account_info['expiration_date'] ) ) ) ; date and set $expiration_date = date('Y-m-d', strtotime('+'.$SubscriptionPlans[ the account’s $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths'].' months', strtotime( $expiration_date ) ) ); product to echo "expiration date will be updated to ".$expiration_date.".\n"; prepaid $r = update_expiration_date( $i_account, $expiration_date ); private. 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 } else { transaction err("paypal transaction failed " . $account- failed, we >account_info['i_account'] ); send an email email_automatic_payment_method_failed( $account ); echo "paypal transaction failed.\n"; to the } customer.

In case the } else { authorization email_automatic_payment_paypal_not_approved( $account ); is not

echo "paypal is not approved. customer must check it emails\n"; approved, we

} send an email to the customer. In case there } else { was a renewal echo "no payment method and auto renewal. we will remove the auto option but renewal\n"; not set set_auto_renewal( $account->account_info['i_account'], FALSE ); } payment method, we have to remove the renewal option. In case that } else { there was no

Page 49/65 echo "no auto renew.\n"; auto-renwal, update_renew_timestamp( $i_account, $current_time->mysql_datetime ); we must tell email_no_renewal_expiration_date_ends_in_X_days( $account , $day_diff ); 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. This may no } elseif ( $day_diff < 0 ) { occurs but if echo "expiration is reached. we must set the product back to normal prepaid we are after and remove subscription date.\n"; the expiration $r = remove_prepaid_private_product( $i_account, $account- >account_info['iso_4217'] ); date, we must if ( $r ){ set back the echo "private prepaid product removed.\n"; product to if ( remove_expiration_date( $i_account ) ){ normal echo "expiration date removed.\n"; prepaid and email_subscription_plan_has_been_removed( $account ); remove } else { expiration err("could not remove expiration date : " . $account- date. >account_info['i_account'] ); } } else { err("could not remove prepaid private account. leave the account blocked : " . $account->account_info['i_account'] ); }

When the } else { expiration echo "expiration date is in the future and no need to renew now.\n"; date above

} the X days in which we must try to renew the account, we do nothing. We di not find } else { expiration echo "no expiration date.\n"; date but the

Page 50/65 remove_prepaid_private_product( $account->account_info['i_account'], $account- account is >account_info['iso_4217'] ); prepaid } private. We must change the product back to prepaid product. This only if ( $last_payment_attempt_failed && $remove_if_no_payment ){ occurs for the $r = remove_prepaid_private_product( $i_account, $account- last payment >account_info['iso_4217'] ); attempt. If it if ( $r ){ fails, we echo "private prepaid product removed.\n"; if ( remove_expiration_date( $i_account ) ){ remove the echo "expiration date removed.\n"; expiration } else { date and the err("could not remove expiration date : " . $account- prepaid >account_info['i_account'] ); private } product. } else { err("could not remove prepaid private account. leave the account blocked : " . $account->account_info['i_account'] ); } }

End of the } loop through accounts. Closing stop(); databases connections. Making a function make_credit_card_transation( $i_customer, $amount = 1, $visible_comment = NULL, $internal_comment = NULL ){ transaction global $ServiceCustomer; with credit global $ServiceAccount; card with # print_r( 'Credit card transaction' ); SOAP API. $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 );

Page 51/65 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 function make_paypal_transaction( $i_customer, $amount, $currency, $visible_comment = NULL, $internal_comment = NULL ){ paypal global $ServiceCustomer; transaction. 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 = "https://account.switzernet.com/customer_info.html"; $cancelUrl = "https://account.switzernet.com/customer_info.html";

$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'];

Page 52/65 $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; }

Page 53/65 Removing the function update_expiration_date( $i_account, $expiration_date = NULL ){ expiration global $ServiceCustomer; date with the global $ServiceAccount; SOAP API. $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 function remove_expiration_date( $i_account ){ expiration global $ServiceCustomer; date with the global $ServiceAccount; SOAP API. $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; }

Setting the function set_auto_renewal( $i_account , $flag ){ auto renewal $text_value = 'no'; to on or of if ( $flag ) { with the SOAP $text_value = 'yes'; } API.

Page 54/65 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; }

Function to function set_prepaid_private_product( $i_account, $currency ){ set the global $ServiceCustomer; product to global $ServiceAccount; prepaid global $PB_Private_Prepaid_Products; private. It $i_product = 33; if ( isset( $PB_Private_Prepaid_Products[ $currency ] ) ){ uses the id of $i_product = $PB_Private_Prepaid_Products[ $currency ]; the } else { subscription error_log("new i_product not found. using default ".$i_product ); plan and the } general config $AccountInfo = array( file to 'i_account' => $i_account, subscription 'i_product' => $i_product, plans. ); $UpdateAccountRequest = array( 'account_info' => $AccountInfo ); try { $AddUpdateAccountResponse = $ServiceAccount- >update_account($UpdateAccountRequest); } catch (SoapFault $fault) { err("Soap error :".$fault); return false; } return true; }

Page 55/65 Removing of function remove_prepaid_private_product( $i_account, $currency ){ the prepaid global $ServiceCustomer; private global $ServiceAccount; product. The global $PRODUCT; $i_product = 4; global if ( isset( $PRODUCT[ $currency ]['pre']['i_product'] ) ){ variable $i_product = $PRODUCT[ $currency ]['pre']['i_product']; ‘PRODUCT’ is } else { set in the error_log("new i_product not found. using default ".$i_product ); general } comfiguration $AccountInfo = array( file for the 'i_account' => $i_account, products. It 'i_product' => $i_product, looks for the ); prepaid $UpdateAccountRequest = array( product in the 'account_info' => $AccountInfo corresponding ); currencies. try { $AddUpdateAccountResponse = $ServiceAccount- >update_account($UpdateAccountRequest); } catch (SoapFault $fault) { err("Soap error :".$fault); return false; } return true; }

This function function update_renew_timestamp( $i_account, $datetime ){ update the global $ServiceCustomer; custom field global $ServiceAccount; that echo "updating the auto renew\n"; represents try { $text_value = $datetime; the timestamp on $CustomFieldsValuesInfo = array( which the 'name' => 'Survey timestamp', script //'db_value' => $i_subscription_plan, processed the 'text_value' => $text_value account. );

$custom_fields_values = array();

array_push($custom_fields_values, $CustomFieldsValuesInfo);

$UpdateAccountCustomFieldsValuesRequest = array(

Page 56/65 '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; }

A general function send_info_mail( $subject, $body ){ function to send emails. $mail_From = "[email protected]"; $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 = "[email protected]"; $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); }

Connection to function start(){ all the slave_db_connect(); databases. master_db_connect(); web_db_connect(); soap_connect(); }

Disconnect function stop(){

Page 57/65 global $LocalMysqli ; everything global $MasterMysqli ; before global $SlaveMysqli ; closing. global $ServiceAccount ; global $ServiceCustomer; $LocalMysqli ->close(); $MasterMysqli ->close(); $SlaveMysqli ->close(); $ServiceAccount ->_logout(); $ServiceCustomer ->_logout(); }

Connection to function slave_db_connect(){ the slave global $SlaveMysqli; database. $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 function master_db_connect(){ the master global $MasterMysqli; database. $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 function web_db_connect(){ the web global $LocalMysqli; database. $filename = 'connections/local.mysqli.class.php'; if(!@include_once( $filename ) ) throw new Custom_Exception( "Failed to include ".

Page 58/65 $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 function soap_connect(){ SOAP API. 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('https://slave.switzernet.com:8444', 'Admin', 'Customer'); $session_id = $ServiceCustomer->_login($SOAP_user, $SOAP_pass); $ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', 'Admin', 'Account'); $ServiceAccount->_setSessionId($session_id); } catch (SoapFault $e) { throw new Custom_Exception("Could not connect to porta-billing SOAP server !"); } return $session_id; }

Function to function stmt_bind_assoc (&$stmt, &$out) { retrieve $data = $stmt->result_metadata(); results of a $fields = array(); MySQL query $out = array(); with prepaid $fields[0] = $stmt;

Page 59/65 $count = 1; statements. It while($field = $data->fetch_field()) { return the $fields[$count] = &$out[$field->name]; data in a $count++; hash. } call_user_func_array('mysqli_stmt_bind_result', $fields); }

An error function err( $message , $mail = TRUE ){ function that try { send emails. mail('[email protected]','prepay private survey error', $message . "\n\n" . "Message sent from web server script:" . __FILE__); echo $message."\n"; } catch(Exception $e) { echo $e."\n"; } }

An extension class Custom_Exception extends Exception{ of the

extension public function __construct($message = null, $code = 0, Exception $previous = null) { class that $this->err( $message , $mail = TRUE ); send emails. It } is useful for SOAP request function err( $message , $mail = TRUE ){ for example. try { mail('[email protected]','prepay private survey error', $message . "\n\n" . "Message sent from web server script:" . __FILE__); echo $message."\n"; } catch(Exception $e) { echo $e."\n"; } } }

# emails :

The email function email_automatic_payment_method_failed ( $account ){ sent to #print_r($account); customer global $current_time; informing that global $SubscriptionPlans; global $prepaid_interface_management_url; its automatic include "configurations/currency_prices.php"; payment $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ failed.

Page 60/65 '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 .= '

'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",

"; $body .= '

'.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.') . '

'; $body .= '

'.l('In order to continue to benefit of your prepaid subscription, thank you to update your automatic payment information in your').' '.l('prepaid subscription management web interface'). ' ' . l('and also to verify that your credit card/paypal account have available funds to process the payment.').'

'; $body .= '

'.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'] . ').

'; $body .= '

'.l('Best regards').',
'; $body .= l('Switzernet team').'

';

# . 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 ); }

An email to function email_automatic_payment_paypal_not_approved ( $account ){ the customer global $current_time; informaing global $SubscriptionPlans; that the global $prepaid_interface_management_url; include "configurations/currency_prices.php"; PayPal $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ account 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ authorization $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths']; is not $subject = ''; approved. $body = ''; $subject .= l('The automatic paiment for the renewal of your subscription failed'); $body .= '

'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' .

Page 61/65 $account->customer_info['lastname'].",

"; $body .= '

'.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.') . '

'; $body .= '

'.l('In order to continue to benefit of your prepaid subscription, thank you to approve the PayPal authorization in your').' '.l('prepaid subscription management web interface'). ' ' . l('and also to verify that your paypal account have available funds to process the payment.').'

'; $body .= '

'.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'] . ').

'; $body .= '

'.l('Best regards').',
'; $body .= l('Switzernet team').'

';

send_email_to_customer( $account->customer_info['email'], $subject, $body ); }

This email is function email_no_renewal_expiration_date_ends_in_X_days( $account, $number_of_days ){ sent when the global $current_time; customer has global $SubscriptionPlans; no renewal global $prepaid_interface_management_url; option include "configurations/currency_prices.php"; activated or $amount = ( $SubscriptionPlans[ $account->account_info['subscription_plan_id'] ][ no credit card 'MonthlyFees' ][ $account->account_info['iso_4217'] ] ) * $SubscriptionPlans[ set. It informs $account->account_info['subscription_plan_id'] ]['RenewalPeriodMonths']; the customer

$subject = ''; in how many $body = ''; days the $subject .= l('Your subscription for your VoIP account') . ' ' . $account- >account_info['id'] . ' ' . l('will expire soon.'); subscription plan expires. $body .= '

'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",

";

$body .= '

'.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') ) . '.

' ;

Page 62/65 $body .= '

'.l('In order to continue to benefit its advantages, thank you to renew it from your').' ' . l('prepaid subscription management web interface') . '

';

$body .= '

'.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'] . ').

';

$body .= '

'.l('Best regards').',
'; $body .= l('Switzernet team').'

'; send_email_to_customer( $account->customer_info['email'], $subject, $body );

}

The email function email_subscription_plan_has_been_removed( $account ){ informing that global $PRICES; the $subject = ''; subscription $subject .= l('Your subscription for your VoIP account') . ' ' . $account- plan has been >account_info['id'] . ' ' . l('has expired.'); removed and the product has changed. $body = '';

$body .= '

'.l('Dear') . ' ' . $account->customer_info['firstname'] . ' ' . $account->customer_info['lastname'].",

";

$body .= '

'.l('We would like to inform you that the subscription you choosed for your VoIP account') . ' ' . $account->account_info['id'] . ' ' . l('has expired.');

$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'] . ').

';

send_email_to_customer( $account->customer_info['email'], $subject, $body );

}

General

Page 63/65 function send_email_to_customer( $email, $subject, $body ){ function to if (filter_var($email, FILTER_VALIDATE_EMAIL)) { send the $mail = new PHPMailer; email to

$mail->CharSet = 'UTF-8'; customer. $mail->From = '[email protected]'; $mail->FromName = 'Switzernet'; $mail->addAddress( $email ); // Add a recipient $mail->addAddress( '[email protected]' ); // Add a recipient $mail->AddReplyTo( '[email protected]' , 'Billing'); $mail->Subject = $subject; $mail->Body = $body; $mail->IsHTML(); return $mail->send(); } else { return false; } }

This class class pid { manage the protected $filename; running public $already_running = false; process and function __construct($directory) { $this->filename = $directory . '/' . basename($_SERVER['PHP_SELF']) . '.pid'; permit to if(is_writable($this->filename) || is_writable($directory)) { check if if(file_exists($this->filename)) { anyone is $pid = (int)trim(file_get_contents($this->filename)); running in the if(posix_kill($pid, 0)) { same tim. $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); } } }

Page 64/65 ?>

* * *

Copyright © 2018 by Switzernet

Page 65/65

Recommended publications