PAYPAL ADAPTIVE PAYMENTS
AND
BILLING INTEGRATION

Document created on 2014-10-02
Nicolas Bondier

 

[pdf][doc][htm]

 

 

 

 

 

*                  *                  *

Copyright © 2014 by Switzernet

Contents

Introduction. 3

Adding PayPal in porta-billing. 3

Creating a PayPal processor. 3

Adding In the database. 3

Adding to the porta-billing interface. 3

Adding to the customer interface. 4

Removing PayPal from the “Pay Now” interface. 4

Modify top row if PayPal is choose for redirecting to normal payment page. 4

Add the PayPal button. 6

Remove payment errors. 11

Preapproval 13

Redirect to PayPal preapproval payment page. 13

Get preapproval notifications. 21

Payment script. 28

Process PayPal payments. 28

Links. 42

 


Introduction

This document describes the PayPal integration with our customer web interface and system for adding PayPal adaptive payments.

Adding PayPal in porta-billing

Legend : Modified code

Creating a PayPal processor

Adding In the database

In the master database, add the new processor:

INSERT INTO Online_Payment_Processors (

  processor

  ,web_link

  ,handler

  ,callback

  ,ext_auth

  ,obsolete

  ,remittance

  )

VALUES (

  'PayPal'

  ,'https://www.paypal.com/'

  ,NULL

  ,NULL

  ,'N'

  ,'N'

  ,'N'

  );

 

Adding to the porta-billing interface

Add a PayPal icon in the folder of payments methods icons /home/porta-admin/apache/images/PMIcons/

 

Know you would be able to add a new payment system with the PayPal payment method. Login and passwords does not care.

 

And for a currency, add the new payment system:

 

Adding to the customer interface.

 

Removing PayPal from the “Pay Now” interface

The billing cannot process a normal Pay action with PayPal. If no credit card is set and the customer wants to pay, he will see the PayPal in the list of payment methods. It must be removed.

[/home/porta-admin/apache/make_payment.mcomp] line 442

  <td><text>Payment Method</text></td>

  <td  colspan="3"><select name=i_payment_method onChange="javascript:ChangePaymentMethod()">

%          foreach my $row (@$payment_methods) {

%      if ( $row->{payment_method} ne 'PayPal' ){

               <option value="<% $row->{i_payment_method} %>" ext_auth="<% $row->{ext_auth}%>"

                            <% $row->{i_payment_method} == $ARGS{i_payment_method} ? 'selected':'' %>

                            payment_method="<% $row->{payment_method} |js %>"><%$row->{name}|h%></option>

%      }

%          }

 

Modify top row if PayPal is choose for redirecting to normal payment page.

[/home/porta-admin/apache/top-table.html] line 16

if ( !$content ) {

    if ( $ARGS{href} =~ /^http:\/\/pay\.switzernet.com/ ){

        $content = '<li><a target="_blank" onclick="return PB_confirmLeavePage()" href="'.$ARGS{href}.'">'. $str  .'<\/a>';

    } else {

        $content = '<li><a onclick="return PB_confirmLeavePage()" href="'.$ARGS{href}.'">'. $str  .'<\/a>';

    }

}

 

[/home/porta-admin/apache/customer_selfcare/top-table.html] line 46

<&|/core.mcomp:.pb100 &>

%   my $paypal_result = "";

%   if ( defined( $info->{i_credit_card} ) ){

%       my $porta_dbh = DBI->connect( "xxxx", "xxxx", "xxxx" ) or die "Connexion impossible à la base de données porta-billing sur porta-billing-master !";

%       $paypal_result = $porta_dbh->selectrow_array( 'SELECT pm.name FROM Credit_Cards cc INNER JOIN Payment_Methods pm ON cc.i_payment_method=pm.i_payment_method WHERE i_credit_card = '.$info->{i_credit_card}.' LIMIT 1', undef );

%       $porta_dbh->disconnect;

%   }

% if ( $processor->{processor} ) {

%   if ( $paypal_result ne 'PayPal' ) {

    <& /top-table.html:.lset, level => $ph->{level}, i => $cur_numb, is => \$is, href => "/make_payment.html", attr => 'Make Payment', str => '<jstext>mn_Make_Payment</jstext>' &>

%   } else {

    <& /top-table.html:.lset, level => $ph->{level}, i => $cur_numb, is => \$is, href => "http://pay.switzernet.com?action=payment&i_customer=".$info->{acc}, attr => 'Make Payment', str => '<jstext>mn_Make_Payment</jstext>' &>

%   }  

%     if ($periodical_en && $info->{ppm_enabled} eq 'Y') {

    <& /top-table.html:.lset, level => $ph->{level}, i => $cur_numb, is => \$is, href => "/p_payment.html", attr => 'Periodical Payments', str => '<jstext>mn_Periodical_Payments</jstext>' &>

%     }

% }

</&>


 

 

Add the PayPal button

 

[/home/porta-admin/apache//switzernet/paypal/paypal_preappoval_info.mcomp]

Code

Comment

<%args>

$info

$card_info

</%args>

 

 

Beginning of the mason script.

 

<%perl>

my $test_variable = $card_info;

my $i_customer = $info->{acc};

 

my $database = " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ";

my $host = " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ";

my $user = " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ";

my $pass = " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ";

 

Database logins and passwords.

 

my $AUTH_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

 

Shared secret key.

 

my $TARGET_URL = "http://switzernet.com/3/public/140910-paypal-recurring/paypalPreapprovalProcess.php";

 

URL on which the customer must be redirected.

 

my $BUTTON_PARAMS = {

  'i_customer' => $i_customer,

};

 

 

Parameters that we will send and hash.

 

# GETTING STATUS OF PREAPPORVAL

 

my $dbh = DBI->connect( "dbi:mysql:$database:$host:xxxx", $user, $pass ) or die "Couldn't connect to database: " . DBI->errstr;

my $sql = "SELECT senderEmail , approved FROM CustomerPayPalPreapprovedPayments WHERE i_customer = ? ;";

my $sth = $dbh->prepare($sql);

 

$sth->execute( $i_customer ) or die DBI->errstr;

 

my $result = $sth->fetchrow_hashref();

 

Getting the status of the preapproval.

 

 

 

my $status_html = '';

my $button_text = 'Give a PayPal authorization';

if ( defined( $result->{approved} ) ){

  if ( $result->{approved} ){

    $status_html = 'Approved';

    $button_text = "Give a new PayPal authorization";

  } else {

    $status_html = 'Authorization pending';

  }

} else {

  $status_html = 'No paypal authorization defined';

}

$sth->finish();

$dbh->disconnect;

 

Displaying the status.

 

# CREATING THE LINK WITH SHA AUTHENTICATION

use URI::Escape;

use Digest::SHA1  qw(sha1_hex);

 

 

# ---

 

my $SHA1_KEY = '';

my $URL_PARAMS = '';

my $BUTTON_URL = '';

 

foreach my $key (sort keys %$BUTTON_PARAMS) {

  $SHA1_KEY .= uri_escape( $key."=".$BUTTON_PARAMS->{$key} ) . $AUTH_KEY;

  $URL_PARAMS .= uri_escape( $key ) ."=" . uri_escape( $BUTTON_PARAMS->{$key} ) . "&";

}

$SHA1_KEY = sha1_hex($SHA1_KEY);

$BUTTON_URL = $TARGET_URL . "?" . $URL_PARAMS . "AUTH_KEY=" . $SHA1_KEY;

 

# ---

 

This is the process to build the URL on which the customer will go for the preapproval.

 

It was necessary to protect the URL in order to make impossible to customer to override other customers pre-approvals.

 

The AUTH_KEY parameter will contain a hash of the URL parameters concatenated with the secret key.

 

This parameter will be verified in the preapproval page that will redirect to PayPal.

 

</%perl>

    <table border="0">

        <tr>

            <td style="width: 23%;"></td>

            <td><br>Status : <% $status_html %></td>

        </tr>

        <tr>

            <td style="width: 23%;"><br></td>

            <td><br>

            <input type="button" onclick="window.location.href='<% $BUTTON_URL %>';" value="<% $button_text %>" />

            </td>

        </tr>

    </table>

 

 

Displaying of the status and button.

 


 

[/home/porta-admin/apache/switzernet/paypal/paypal_preappoval_info.mcomp] line 244

<div ID="PayPalDiv" style="display: none; position: absolute;">

    <& /switzernet/paypal/paypal_preappoval_info.mcomp, info => $info, card_info => $card_info &>

</div>

 

 

[/home/porta-admin/apache/switzernet/paypal/paypal_preappoval_info.mcomp] line 178

 

   if (pm == "PayPal") {

        hide_paymentInfo();

//      CardNoText.innerHTML = "test";

        elemCVV.style.display = 'none'

        CardExpTD1.style.display = 'none'

        CardExpTD2.style.display = 'none'

        NameOnCard.innerHTML = "<text>PM Account Name</text>"

        CardNoText.innerHTML = "<text>PM Account number</text>"

        elemCityReq.style.display = ''

 

        document.getElementById('PayPalDiv').style.display = "";

        document.getElementById('PayPalDiv').style.visibility = "visible";

 

    }

 

[/home/porta-admin/apache/switzernet/paypal/paypal_preappoval_info.mcomp] line 40

function hide_paymentInfo() {

  document.getElementById('CreditCardDiv').style.visibility = 'hidden';

    document.getElementById('ExtAuthDiv').style.visibility = 'hidden';

    document.getElementById('PayPalDiv').style.visibility = 'hidden';

}

 

[/home/porta-admin/apache/switzernet/paypal/paypal_preappoval_info.mcomp] line 65

   if (ext_auth != 'Y' && meth != '' && meth > 2 && pm != 'PayPal') {

 

Remove payment errors

 

[/home/porta-admin/site_lib/Porta/Tasks.pm] line 754

       if($payment_module->is_paypal) {

            $self->{i_env} = $old_env;

            Porta::TaskLog->info('PayPal must be managed externaly');

            $payment_module->clean_is_paypal();

            next;

        }

 

        my $mail_tmpl = new Porta::Mail_Template;

 

[/home/porta-admin/site_lib/Porta/Payment.pm] line 67

my $PAYPAL_KEY = 'paypal_not_supported';

 

[/home/porta-admin/site_lib/Porta/Payment.pm] line 1258

   } elsif ( $processor->{processor} eq 'PayPal' ) {

        $self->{errstr} = "[custom switzernet message] PayPal is not supported";

        $self->{i_env} = $old_env;

        $self->{ $PAYPAL_KEY } = 1;

        print $LOG localtime() . ": " . $self->{errstr} . "\n";

        return undef;

    } else {

        $self->{errstr} = "Payment Processor $processor->{processor} not supported yet.";

 

[/home/porta-admin/site_lib/Porta/Payment.pm] line 4612

sub clean_amount_too_small {

    my $self = shift;

    $self->{ $SMALL_AMOUNT_KEY } = 0;

}

 

sub is_paypal {

    my $self = shift;

    return $self->{ $PAYPAL_KEY } ? 1 : 0;

}

 

sub clean_is_paypal {

    my $self = shift;

    return $self->{ $PAYPAL_KEY } = 0;

}

 


 

Preapproval

Redirect to PayPal preapproval payment page.

[paypalPreapprovalProcess.php]

Code

Comment

require_once('include/portabilling.config.php');

require_once("classes/PortaBillingSoapClient.php");

require_once("include/db.config.php");

require_once('PPBootStrap.php');

 

Includes

 

$SOAP_user = 'xxxxxxxx';

$SOAP_password = 'xxxxxxxx';

 

define("DEFAULT_SELECT", "- Select -");

 

$sipAccount = '';

$i_customer = '';

$account_currency = '';

$startingDate = date("Y-m-d");

$cancelUrl    = "";

$returnUrl    = "";

 

Some variables used latter.

 

$ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', 'Admin', 'Account');

$session_id = $ServiceAccount->_login($SOAP_user, $SOAP_password);

$ServiceAccount->_setSessionId($session_id);

 

 

Connection to SOAP.

// GET FROM PORTA-BILLING

 

if ( isset( $_GET['i_customer'] ) &&  preg_match('/^[0-9]+$/', $_GET['i_customer'] )  ){

 

  if ( ! isset( $_GET['AUTH_KEY'] ) ){

    echo "You are not authenticated !\n";

    $ServiceAccount->_logout();

    exit;

  }

 

 

 

 

 

Get the customer id for which we have to make a preapproval request. The URL is composed of i_customer and an authentication key. The authentication key is a hash of the secret and parameters.

 

  $AUTH_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

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

 

Here we have the same secret key defined.

 

We recalculate the hash from the secret key and paramaters.

 

  if ( $SHA1_KEY != $_GET['AUTH_KEY'] ){

    echo "You are not authenticated !\n";

    $ServiceAccount->_logout();

    exit;

  }

 

If the recalculated hash is the same as the one received in parameters, it means the URL comes from the porta-billing server. If not, we leave.

 

  $i_customer = $_GET['i_customer'];

  $GetAccountListRequest = array( 'i_customer' => $i_customer, 'offset' => NULL, 'limit' => NULL, 'i_batch' => NULL );

  $GetAccountListResponse = $ServiceAccount->get_account_list($GetAccountListRequest);

  $account_list = $GetAccountListResponse->account_list;

  foreach ($account_list as $account_info) {

    if ( $account_info->bill_status != 'C' ){

      $sipAccount = $account_info->id;

      $account_currency = $account_info->iso_4217;

      break;

    }

  }

 

 

 

 

 

With SOAP, we search for the customer account and currency.

 

  $returnUrl = "https://account.switzernet.com/customer_info.html?tab=p_i";

  $cancelUrl = "https://account.switzernet.com/customer_info.html?tab=p_i";

}

 

$ServiceAccount->_logout();

 

 

 

Here, we define the return URLs to send to PayPal. They will be used for redirection to the porta-billing slave server.

 

 

if ( $sipAccount == '' ){

  echo "No account defined";

  exit;

}

 

If no account has been found, we leave.

$requestEnvelope = new RequestEnvelope("en_US");

$preapprovalRequest = new PreapprovalRequest($requestEnvelope, $cancelUrl,

$account_currency, $returnUrl, $startingDate);

Beginning of the construction of the PayPal request.

$preapprovalRequest->paymentPeriod                 = 'NO_PERIOD_SPECIFIED';

This is the day of each payment. We do not have specified day. Customer can choose to pay anytime.

$preapprovalRequest->pinType                       = 'NOT_REQUIRED';

 

No pin is required.

$preapprovalRequest->feesPayer                     = 'EACHRECEIVER';

 

Each receiver (currently there is only one).

$preapprovalRequest->ipnNotificationUrl            = 'http://switzernet.com/public/140911-paypal-preapproval-notification/sandbox.php';

The URL on which PayPal will send the notifications.

$preapprovalRequest->endingDate                    = date('Y-m-d', strtotime('+364 days)) ."\n";

The ending date. The default maximum value is one year. We fix this to the maximum for the moment.

 

$preapprovalRequest->maxTotalAmountOfAllPayments   = '2000';

 

 

The maximum total amount of all payment is by default $2000. We fix this setting to the maximum too.

 

$preapprovalRequest->paymentPeriod                 = 'NO_PERIOD_SPECIFIED';

 

We do not specify a payment period. Customer can pay at any time.

 

$preapprovalRequest->maxAmountPerPayment           = '300';

 

It is mandatory to fix a maximum amount per payment. We set 300 which should not block normal customer payments.

 

$service = new AdaptivePaymentsService(Configuration::getAcctAndConfig());

try {

      /* wrap API method calls on the service object with a try catch */

      $response = $service->Preapproval($preapprovalRequest);

} catch(Exception $ex) {

      require_once 'Common/Error.php';

      exit;

}

 

 

 

Sending of the approval request.

 

$DEBUG = FALSE;

 

 

Debug variable.

if ( $DEBUG ){

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<head>

  <title>PayPal Adaptive Payments - Preapproval</title>

  <link href="Common/sdk.css" rel="stylesheet" type="text/css" />

  <script type="text/javascript" src="Common/sdk_functions.js"></script>

</head>

<body>

      <div id="wrapper">

            <img src="https://devtools-paypal.com/image/bdg_payments_by_pp_2line.png"/>

            <div id="response_form">

                  <h3>Preapproval</h3>

      <?php

      $ack = strtoupper($response->responseEnvelope->ack);

      if($ack != "SUCCESS"){

            echo "<b>Error </b>";

            echo "<pre>";

            print_r($response);

            echo "</pre>";

      } else {

            echo "<pre>";

            print_r($response);

            echo "</pre>";

            // Redirect to paypal.com here

            $token = $response->preapprovalKey;

            $payPalURL = 'https://www.sandbox.paypal.com/webscr&cmd=_ap-preapproval&preapprovalkey='.$token;

            echo "<table>";

            echo "<tr><td>Ack :</td><td><div id='Ack'>$ack</div> </td></tr>";

            echo "<tr><td>PreapprovalKey :</td><td><div id='PreapprovalKey'>$token</div> </td></tr>";

            echo "<tr><td><a href=$payPalURL><b>Redirect URL to Complete Preapproval Authorization</b></a></td></tr>";

            echo "</table>";

      }

      require_once 'Common/Response.php';      

      ?>

            </div>

      </div>

</body>

</html>

 

 

In case of debug.

We display the content of the request and PayPal responses.

 

A link is generated to continue to the PayPal preapproval page.

 

<?php

} else {

  $ack = strtoupper($response->responseEnvelope->ack);

  if($ack != "SUCCESS"){

    echo "<b>Error </b>";

    echo "<pre>";

    print_r($response);

    echo "</pre>";

  } else {

    $token = $response->preapprovalKey;

    $mysqli = new mysqli(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_DATABASE);

    if (mysqli_connect_errno()) {

        printf("Échec de la connexion : %s\n", mysqli_connect_error());

        exit();

    }

    $stmt = $mysqli->prepare("REPLACE INTO `CustomerPayPalPreapprovedPayments` (i_customer, preapproval_key) VALUES (?, ?)");

    $i_customer = chomp($i_customer);

    $token = chomp($token);

    $stmt->bind_param('is', $i_customer, $token );

    $stmt->execute();

    if ($stmt->error){

      alert($stmt->error);

    }

    $stmt->close();

    $mysqli->close();

 

    $payPalURL = 'https://www.sandbox.paypal.com/webscr&cmd=_ap-preapproval&preapprovalkey='.$token;

    header('Location: '.$payPalURL);

  }

}

 

 

If we are not in debugging mode, we verify the answer from PayPal.

 

If the preapproval request is accepted, we save the preapproval key we received in the database and the i_customer.

 

 

 

/*

DROP TABLE `CustomerPayPalPreapprovedPayments`;

CREATE TABLE `CustomerPayPalPreapprovedPayments` (

  id              INT(10) NOT NULL AUTO_INCREMENT,

  i_customer      INT(10) UNSIGNED NOT NULL UNIQUE,

  preapproval_key VARCHAR(32) NOT NULL UNIQUE,

  startingDate    DATETIME,

  endingDate      DATETIME,

  currency_code   VARCHAR(3),

  approved        TINYINT(1) NOT NULL DEFAULT 0,

  senderEmail     VARCHAR(255),

  PRIMARY KEY (id),

  KEY (i_customer),

  KEY (preapproval_key),

  KEY (startingDate),

  KEY (endingDate),

  KEY (approved)

);

*/

 

 

 

 

function alert( $string = '' ){

  echo "<script>

  $(document).ready(function (){

      alert(\"$string\");

  });

</script>";

}

?>

 

An alert function for debugging

 

Get preapproval notifications

               

Code

Comment

<?php

require_once("configure.php");

$sandbox = TRUE;

 

Files required

 

header('HTTP/1.1 200 OK');

 

Send an empty HTTP 200 OK response to acknowledge receipt of the notification

 

$starting_date    = $_POST['starting_date'];

$currency_code    = $_POST['currency_code'];

$sender_email     = $_POST['sender_email'];

$preapproval_key  = $_POST['preapproval_key'];

$approved         = $_POST['approved'];

$transaction_type = $_POST['transaction_type'];

$preapproval_key = chomp($preapproval_key);

 

 

Assign payment notification values to local variables

 

$mail_To      = "cash@switzernet.com";

$mail_From    = "PayPal_IPN@switzernet.com";

$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 preferences.

 

if ( $sandbox == TRUE ){

  $payment_currency = 'CHF';

  $PayPalURL = "www.sandbox.paypal.com";

  $mail_To   = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

 

  $mail_Header = "";

  $mail_Header .= 'From: ' . $mail_From                                                           . "\r\n";

  $mail_Header .= 'Reply-To: '.$mail_To                                                           . "\r\n";

  $mail_Header .= 'Content-type: text/plain; charset=utf-8'                                       . "\r\n";

  $mail_Header .= 'X-Mailer: PHP/' . phpversion()                                                 . "\r\n";

  $mail_Subject = "PayPal new payment notification arrived";

 

  $mail_Body    = "Notification details on ".date("Y-m-d H-i-s").":\n\n";

 

  foreach ($_POST as $key => $value) {

    $mailreq .= "$key = $value\n";

    $mail_Body  .= "$key:$value\n";

  }

  $mail_Body   .= $mail_Footer;

 

  mail($mail_To, $mail_Subject, $mail_Body, $mail_Header);

 

} else {

  $PayPalURL = "www.paypal.com";

}

 

 

If we are in sandbox mode, we send an email with received data, change the recipeits of the emails and change the connections settings.

 

 

$message_id_prefix = 'paypal-approval.'.$preapproval_key;

 

$mail_From    = "PayPal_IPN@switzernet.com";

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

 

 

Fixing an id for the future email that will be sent and replay in threads.

 

 

 

$req = 'cmd=_notify-validate';

$mailreq = "";

 

foreach ($_POST as $key => $value) {

  $mailreq .= "$key = $value\n";

  $value = urlencode(stripslashes($value));

  $req  .= "&$key=$value";

}

 

 

Build the required acknowledgement message out of the notification just received

 

Add 'cmd=_notify-validate' to beginning of the acknowledgement.

 

Loop through the notification NV pairs. Encode the values and add  the NV pairs to the acknowledgement.

 

$header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";

$header .= "Host: ".$PayPalURL."\r\n";

$header .= "Content-Type: application/x-www-form-urlencoded\r\n";

$header .= "Connection: close\r\n";

$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

 

 

Set up the acknowledgement request headers.

 

 

$fp = fsockopen('ssl://'.$PayPalURL, 443, $errno, $errstr, 30);

 

Open a socket for the acknowledgement request

 

fputs($fp, $header . $req);

 

Send the HTTP POST request back to PayPal for validation

 

$reception = "[";

$i = 0;

while (!feof($fp)) {                     // While not EOF

  $res = fgets($fp, 1024);               // Get the acknowledgement response

 

 

Get the acknowledgement response in the socket.

 

  $reception .= "[".chomp($res)."]\n";

  if (strcmp (chomp($res), "VERIFIED") == 0) {  // Response contains VERIFIED - process notification

    // Authentication protocol is complete - OK to process notification contents

    $mail_Header = "";

    $mail_Header .= 'From: ' . $mail_From                                                           . "\r\n";

    $mail_Header .= 'Reply-To: '.$mail_To                                                           . "\r\n";

    $mail_Header .= 'Message-Id: <'$message_id_prefix . '@ipn.switzernet.com>'                   . "\r\n";

    $mail_Header .= 'Content-type: text/plain; charset=utf-8'                                       . "\r\n";

    $mail_Header .= 'X-Mailer: PHP/' . phpversion()                                                 . "\r\n";

    $mail_Subject = "PayPal preapproval notification / preapproval_key:".$preapproval_key." / sender_email:".$sender_email." / approved:".$approved."";

    $mail_Body    = "A preapproval as been sent by paypal.\n";

    $mail_Body   .= "\n";

    $mail_Body   .= "**********************************************\n";

    $mail_Body   .= "*          Preapproval details               *\n";

    $mail_Body   .= "**********************************************\n";

    $mail_Body   .= "\n";

    $mail_Body   .= "starting_date    : " . $starting_date     . "\n";

    $mail_Body   .= "currency_code    : " . $currency_code     . "\n";

    $mail_Body   .= "sender_email     : " . $sender_email      . "\n";

    $mail_Body   .= "preapproval_key  : " . $preapproval_key   . "\n";

    $mail_Body   .= "approved         : " . $approved          . "\n";

    $mail_Body   .= "transaction_type : " . $transaction_type  . "\n";

    $mail_Body   .= $mail_Footer;

    mail($mail_To, $mail_Subject, $mail_Body, $mail_Header);

 

 

The answer is verified.

 

We send the preapproval depails by email.

 

    if ( $approved == 'true' ){ // The customer approved

      $i_customer = '';

 

      $con = mysql_connect(DB_SERVER,DB_SERVER_USERNAME,DB_SERVER_PASSWORD);

      mysql_select_db(DB_DATABASE) or die(mysql_error());

      $req = "SELECT i_customer FROM `CustomerPayPalPreapprovedPayments` WHERE preapproval_key = '".$preapproval_key."' LIMIT 1";

      $result = mysql_query($req);

      $value = mysql_fetch_object($result);

      $i_customer = $value->i_customer;

 

 

The customer approved, we search the i_customer in the local database from the preapproval key.

 

      if ( $i_customer == '' ){

        $mail_Subject = "[preapproval_key not found] PayPal preapproval notification / preapproval_key:".$preapproval_key." / sender_email:".$sender_email." / approved:".$approved."";

        $mail_Header = "";

        $mail_Header .= 'From: ' . $mail_From                                                           . "\r\n";

        $mail_Header .= 'Reply-To: '.$mail_To                                                           . "\r\n";

        $mail_Header .= 'Message-Id: <'$message_id_prefix . '.account_not_found@ipn.switzernet.com>' . "\r\n";

        $mail_Header .= 'References: <' . $message_id_prefix . '@ipn.switzernet.com>'                   . "\r\n";

        $mail_Header .= 'In-Reply-To: <'. $message_id_prefix . '@ipn.switzernet.com>'                   . "\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_Body    = "Could not find the preapproval key [".$preapproval_key."] in database. The approvement is done but the account can not been charged\n";

        $mail_Body .= var_dump($stmt);

        $mail_Body .= $mail_Footer;

        mail($mail_To, $mail_Subject, $mail_Body, $mail_Header);

 

 

We could not find the preapproval key.

 

We send an email for informing of the error.

 

      } else {

        $req = "UPDATE `CustomerPayPalPreapprovedPayments` SET approved = 1, currency_code = '".$currency_code."', senderEmail = '".$sender_email."', startingDate='".$starting_date."' WHERE preapproval_key ='".$preapproval_key."' LIMIT 1";

        $result = mysql_query($req);

       

        if (!$result){

          $mail_Subject = "[unable to process notification] PayPal preapproval notification / preapproval_key:".$preapproval_key." / sender_email:".$sender_email." / approved:".$approved."";

          $mail_Header = "";

          $mail_Header .= 'From: ' . $mail_From                                                           . "\r\n";

          $mail_Header .= 'Reply-To: '.$mail_To                                                           . "\r\n";

          $mail_Header .= 'Message-Id: <'$message_id_prefix . '.account_not_found@ipn.switzernet.com>' . "\r\n";

          $mail_Header .= 'References: <' . $message_id_prefix . '@ipn.switzernet.com>'                   . "\r\n";

          $mail_Header .= 'In-Reply-To: <'. $message_id_prefix . '@ipn.switzernet.com>'                   . "\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_Body    = "Could not update the preapproval key in database. The approvement is done but the account will not been charged\n";

          $mail_Body .= $mail_Footer;

          mail($mail_To, $mail_Subject, $mail_Body, $mail_Header);

        } else {

 

 

We found the key and the customer and we updated the database,

 

We send an email to cash as confirmation.

 

          $mail_Subject = "[done] PayPal preapproval notification / preapproval_key:".$preapproval_key." / sender_email:".$sender_email." / approved:".$approved."";

          $mail_Header = "";

          $mail_Header .= 'From: ' . $mail_From                                                           . "\r\n";

          $mail_Header .= 'Reply-To: '.$mail_To                                                           . "\r\n";

          $mail_Header .= 'Message-Id: <'$message_id_prefix . '.account_not_found@ipn.switzernet.com>' . "\r\n";

          $mail_Header .= 'References: <' . $message_id_prefix . '@ipn.switzernet.com>'                   . "\r\n";

          $mail_Header .= 'In-Reply-To: <'. $message_id_prefix . '@ipn.switzernet.com>'                   . "\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_Body    = "The preapproval key is saved in database. The payments will be processed automatically!\n";

          $mail_Body .= $mail_Footer;

          mail($mail_To, $mail_Subject, $mail_Body, $mail_Header);

        }

 

We were not able to update the database.

 

An email is sent.

 

 

      }

      $mysql->close();

 

 

Closing the locale database.

 

    } else if (strcmp ($res, "INVALID") == 0) {

      // Authentication protocol is complete - begin error handling

      // Send an email announcing the IPN message is INVALID

      $mail_From    = "IPN@switzernet.com";

      $mail_Subject = "INVALID IPN";

      $mail_Header = 'From: ' . $mail_From . "\r\n" .

      'Reply-To: ' . $mail_To. "\r\n" .

      'X-Mailer: PHP/' . phpversion();

      $mail_Body    = $req;

      mail($mail_To, $mail_Subject, $mail_Body, $mail_Header);

    }

 

 

If the answer was invalid, we inform the notification is no valid.

 

  }

}

fclose($fp);  // Close the file

 

 

Closing the socket with PayPal.

 

$reception .= "]";

//mail($mail_To, "Fin de la transaction IPN (index)", "Fin de la transaction IPN (index)\n\n".$reception, $mail_From);

 

 

 

 

function chomp($string){

  return trim(preg_replace('/\s+/', ' ', $string));

}

 

 

Removing some bad characters from the string.

 

?>

 

 

 

Payment script

Process PayPal payments

[execute_payments.php]

Code

Comment

<?php

chdir(dirname(__FILE__))."\n";

 

This script run in crontab. We move to the current directory for using relative paths to required files.

 

require_once("../include/portabilling.config.php");

require_once("../include/paypal.config.php");

require_once("../include/db.config.php");

require_once("../classes/PortaBillingSoapClient.php");

require_once('../PPBootStrap.php');

 

Required configuration and classes.

 

// Lire la BDD des paiements preappouvés

 

$mysqli_local = new mysqli(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_DATABASE);

 

$query = "SELECT i_customer, preapproval_key, startingDate, endingDate, currency_code, approved, senderEmail FROM `CustomerPayPalPreapprovedPayments` WHERE approved = 1 AND ( startingDate < NOW() OR startingDate IS NULL ) AND ( endingDate > NOW() OR endingDate IS NULL OR endingDate = '0000-00-00 00:00:00')";

 

/* Vérifie la connexion */

if (mysqli_connect_errno()) {

    printf("Échec de la connexion : %s\n", mysqli_connect_error());

    exit();

}

 

$preappouved = array();

 

if ($stmt = $mysqli_local->prepare($query)) {

  $stmt->execute();

  $stmt->bind_result($i_customer, $preapproval_key, $startingDate, $endingDate, $currency_code, $approved, $senderEmail);

  while ($stmt->fetch()) {

      $preappouved[$i_customer] = array( 'preapproval_key' => $preapproval_key, 'startingDate' => $startingDate, 'endingDate' => $endingDate, 'currency_code' => $currency_code, 'approved' => $approved, 'senderEmail' => $senderEmail);

      #printf ("%s %s %s %s %s %s %s \n", $i_customer, $preapproval_key, $startingDate, $endingDate, $currency_code, $approved, $senderEmail);

  }

  $stmt->close();

}

 

$mysqli_local->close();

 

Connection to the local database. We get all the preapproved payments.

 

 

 

$session_id = 0;

 

$ServiceCustomer = new PortaBillingSoapClient('https://slave.switzernet.com:8444', 'Admin', 'Customer');

$session_id = $ServiceCustomer->_login(PB_SOAP_LOGIN, PB_SOAP_PASSWORD);

$ServiceCustomer->_setSessionId($session_id);

 

$ServiceAccount = new PortaBillingSoapClient('https://slave.switzernet.com:8444', 'Admin', 'Account');

$ServiceAccount->_login(PB_SOAP_LOGIN, PB_SOAP_PASSWORD);

$ServiceAccount->_setSessionId($session_id);

 

$ServiceInvoice = new PortaBillingSoapClient('https://slave.switzernet.com:8444', 'Admin', 'Invoice');

$ServiceInvoice->_login(PB_SOAP_LOGIN, PB_SOAP_PASSWORD);

$ServiceInvoice->_setSessionId($session_id);

 

Connection to SOAP for the following services: Customer, Account, Invoice.

 

 

$mysqli = new mysqli(PB_SLAVE_DB_SERVER, PB_SLAVE_DB_SERVER_USERNAME, PB_SLAVE_DB_SERVER_PASSWORD, PB_SLAVE_DB_DATABASE, PB_SLAVE_DB_SERVER_PORT);

 

$mysqli_master = new mysqli(PB_MASTER_DB_SERVER, PB_MASTER_DB_SERVER_USERNAME, PB_MASTER_DB_SERVER_PASSWORD, PB_MASTER_DB_DATABASE, PB_MASTER_DB_SERVER_PORT);

 

Connection to the slave and master MySQL databases.

 

$minAllowedPayments = array();

 

$query = "SELECT

  pm.name,

  mac.min_allowed_payment,

  mac.iso_4217 as currency

FROM

  Payment_Methods pm

INNER JOIN

  Merchant_Acct_Payment_Methods mapm

ON

  pm.i_payment_method = mapm.i_payment_method

INNER JOIN

  Merchant_Account_Currency mac

ON

  mapm.i_merchant_account = mac.i_merchant_account

WHERE

  pm.name = 'PayPal';";

 

if ( $stmt = $mysqli->prepare($query) ) {

  $stmt->execute();

  $stmt->bind_result($name, $min_allowed_payment, $currency);

  while ( $stmt->fetch() ) {

    $minAllowedPayments[$currency] = $min_allowed_payment;

  }

  $stmt->close();

} else {

  $minAllowedPayments['USD'] = 10;

  $minAllowedPayments['EUR'] = 10;

  $minAllowedPayments['CHF'] = 10;

}

 

Getting the minimum allowed payments for the payment system in the porta-billing.

 

foreach ($preappouved as $i_customer => $preappouved_info) {

 

Loop for each preapproval found in the database.

 

  $GetCustomerInfoRequest = array( 'i_customer' => $i_customer );

  $customer_info = new stdClass();

  // Getting customer info

  try {

    $GetCustomerInfoResponse = $ServiceCustomer->get_customer_info($GetCustomerInfoRequest);

    $customer_info = $GetCustomerInfoResponse->customer_info;

    //print_r($customer_info);

    echo "\n#\n# CUSTOMER : " , $i , " = " , $customer_info->name , "\n#\n\n";

  } catch(Exception $ex) {

    echo "Couldn't get customer info for i_customer ", $i_customer, "\n";

    continue;

  }

  //print_r($customer_info);

 

We get the customer info we will need later.

 

  if ( $customer_info->ppm_enabled != 'Y' ) {

    echo "Periodical payment not enabled for i_customer ", $i_customer, "\n";

    continue;

  }

 

If the customer do not have periodical payment enabled in the billing, we do not process.

 

  // Getting payment method info (check if it is set to PayPal in its account).

  $GetCustomerPaymentMethodInfoRequest = array( 'i_customer' => $i_customer );

  $payment_method = new stdClass();

  try {

    $GetCustomerPaymentMethodInfoResponse = $ServiceCustomer->get_payment_method_info($GetCustomerPaymentMethodInfoRequest);

    $payment_method_info = $GetCustomerPaymentMethodInfoResponse->payment_method_info;

  } catch(Exception $ex){

    echo "Couldn't get payment_method for i_customer ", $i_customer, "\n";

    continue;

  }

 

We check if the customer saved a payment info. If it is not available, we do not process.

 

  if ( $payment_method_info->payment_method != 'PayPal' ) {

    echo "PayPal is not the payment method defined for i_customer ", $i_customer, "\n";

    continue;

  }

 

If the payment info is different from PayPal, we do not process the customer.

 

  $query = "SELECT pp.i_periodical_payment, ppp.description, pp.amount, pp.balance_threshold, pp.last_payment, pp.from_date, pp.to_date, CURDATE() FROM Periodical_Payments pp INNER JOIN Periodical_Payments_Period ppp ON pp.i_periodical_payment_period = ppp.i_periodical_payment_period WHERE i_object = ? AND object = 'customer' AND discontinued = 'N' AND frozen = 'N' AND from_date <= CURDATE() AND to_date >= CURDATE() ORDER BY stamp DESC LIMIT 1";

 

  if ( $stmt = $mysqli->prepare($query) ) {

    $stmt->bind_param("i", $i_customer);

    $stmt->execute();

    $stmt->bind_result($i_periodical_payment, $description, $amount, $balance_threshold, $last_payment, $from_date, $to_date, $CURDATE);

    if ( $stmt->fetch() ){

      printf(" i_periodical_payment:%d\n description:%s\n amount:%s\n balance_threshold:%s\n last_payment:%s\n from_date:%s\n to_date:%s\n CURDATE:%s\n", $i_periodical_payment, $description, $amount, $balance_threshold, $last_payment, $from_date, $to_date, $CURDATE);

      echo  " balance:".$customer_info->balance."\n";

    } else {

      echo "No record in Periodical_Payments for i_customer ", $i_customer, "\n";

      continue;

    }

    $stmt->close();

  }

 

 

The query for getting the periodical payment settings.

 

We get the current available settings for the customer.

 

If no record is available, we pass to the next customer.

  $timestamp = strtotime( $CURDATE );

 

Getting the timestamp from MySQL database.

 

if ( $description == 'monthly' ){

    $from_date_timestamp = strtotime( $from_date );

    $to_date_timestamp = strtotime( $to_date );

    $today_day_of_month = date('j', $timestamp );

    if ( date('n',$timestamp) == date('n',$to_date_timestamp) ){

      $day_of_month_to_bill = min( date( "t", $timestamp ) , date( "j", $to_date_timestamp ) );

    } else {

      $day_of_month_to_bill = min( date( "t", $timestamp ) , date( "j", $from_date_timestamp ) );

    }

    echo "\n[".date('Y-m-d')."] ";

    if ( $today_day_of_month == $day_of_month_to_bill && $last_payment != $CURDATE ){

      echo "Customer must be charged on ".date('Y-m-d',$timestamp)."\n";

    } else {

      echo "Today ".date('Y-m-d',$timestamp)." is not the billing date\n";

      continue;

    }

 

Starting to read the customer periodical settings.

 

Here we process the monthly recurring payments.

 

We define if the current day is the day to execute the payment.

 

The day to bill is the same day of the month than the starting date (We make the payment earlier in case the day is not present for the current month. Ex 28 days in february).

 

   if ( $amount == 0 ){

      if ( $customer_info->balance < $minAllowedPayments[$customer_info->iso_4217] ){

        echo "Payment (".$customer_info->balance.") must be greater or equal to ".$minAllowedPayments[$customer_info->iso_4217]."\n";

        continue;

      }

      update_last_payment_record( $i_periodical_payment );

      $transaction_result = make_transaction( $customer_info->i_customer, $customer_info->balance, $customer_info->iso_4217 );

      if ( $transaction_result ){

          execute_pb_payment( $customer_info->i_customer, $customer_info->balance, $transaction_result );

      }

    } else {

 

      if ( $amount < $minAllowedPayments[$customer_info->iso_4217] ){

        echo "Payment (".$customer_info->balance.") must be greater or equal to ".$minAllowedPayments[$customer_info->iso_4217]."\n";

        continue;

      }

      update_last_payment_record( $i_periodical_payment );

      $transaction_result = make_transaction( $customer_info->i_customer, $amount, $customer_info->iso_4217 );

      if ( $transaction_result ){

          execute_pb_payment( $customer_info->i_customer, $amount, $transaction_result );

      }

    }

 

We process the amount rules here. $amount equal to 0 is for “Pay Balance” option.

 

If $amount is greater than 0, we must pay the $amount variable.

 

We verify this amount is greater than the minimum allowed payment.

 

We execute the PayPal payment.

 

We update the master database with the current day for not processing twice or more the payment on the same day.

 

 

 

} elseif ( $description == 'weekly' ){

    $from_date_timestamp = strtotime( $from_date );

    $to_date_timestamp = strtotime( $to_date );

    $today_day_of_week = date('N', $timestamp );

    if ( date('Y', $timestamp) == date('Y', $to_date_timestamp) && date('W', $timestamp) == date('W', $to_date_timestamp) ){

      $day_of_week_to_bill = date( "N", $to_date_timestamp );

    } else {

      $day_of_week_to_bill = date( "N", $from_date_timestamp );

    }

    if ( $today_day_of_month == $day_of_month_to_bill && $last_payment != $CURDATE ){

      echo "Customer must be charged on ".date('Y-m-d',$timestamp)."\n";

    } else {

      echo "This is not the billing date ".date('Y-m-d',$timestamp)."\n";

      continue;

    }

 

Here we process the weekly recurring payments.

 

We define if the current day is the day to execute the payment.

 

The day to bill is the same day of the week than the starting date.

 

    if ( $amount == 0 ){

      if ( $customer_info->balance < $minAllowedPayments[$customer_info->iso_4217] ){

        echo "Payment (".$customer_info->balance.") must be greater or equal to ".$minAllowedPayments[$customer_info->iso_4217]."\n";

        continue;

      }

      update_last_payment_record( $i_periodical_payment );

      $transaction_result = make_transaction( $customer_info->i_customer, $customer_info->balance, $customer_info->iso_4217 );

      if ( $transaction_result ){

        execute_pb_payment( $customer_info->i_customer, $customer_info->balance, $transaction_result );

      }

    } else {

      if ( $amount < $minAllowedPayments[$customer_info->iso_4217] ){

        echo "Payment (".$customer_info->balance.") must be greater or equal to ".$minAllowedPayments[$customer_info->iso_4217]."\n";

        continue;

      }

      $transaction_result = make_transaction( $customer_info->i_customer, $amount, $customer_info->iso_4217 );

      update_last_payment_record( $i_periodical_payment );

      if ( $transaction_result ){

        execute_pb_payment(  $customer_info->i_customer, $amount, $transaction_result );

      }

    }

 

We process the amount rules here. $amount equal to 0 is for “Pay Balance” option.

 

If $amount is greater than 0, we must pay the $amount variable.

 

We verify this amount is greater than the minimum allowed payment.

 

We execute the PayPal payment.

 

We update the master database with the current day for not processing twice or more the payment on the same day.

 

} elseif ( $description == 'Balance Driven' ){

 

    if ( $last_payment == $CURDATE ) {

      echo "A payment has been charged today\n";

      continue;

    }

    if ( $customer_info->balance < $balance_threshold ){

      echo "Balance (".$customer_info->balance.") did not reach the balance threshold (".$balance_threshold.")\n";

      continue;

    }

    if ( $amount < $minAllowedPayments[$customer_info->iso_4217] ){

      echo "Minimum (".$customer_info->balance.") payment must be greater or equal to ".$minAllowedPayments[$customer_info->iso_4217]."\n";

      continue;

    }

    $transaction_result = make_transaction( $customer_info->i_customer, $amount, $customer_info->iso_4217 );

    update_last_payment_record( $i_periodical_payment );

    if ( $transaction_result ){

      execute_pb_payment(  $customer_info->i_customer, $amount, $transaction_result );

    }

  }

}

 

In case of “Balance Driven”, we do not need to verify the day. Except for verifying we did not charge the account on the current day.

 

If the balance is lower than the balance threshold, we do not need to pay.

 

We verify that the minimum allowed amount is reached.

 

 

 

$mysqli->close();

$mysqli_master->close();

$ServiceInvoice->_logout();

$ServiceAccount->_logout();

$ServiceCustomer->_logout();

 

Closing all services and MySQL connections.

 

function make_transaction( $i_customer, $amount, $currency ){

  global $preappouved;

 

This is the function for processing the payment with payPal.

 

 

  //print_r($preappouved);

 

  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          = RECEIVER_EMAIL;

  $receiver[0]->amount         = $amount;

  $receiver[0]->primary        = "false";

  $receiver[0]->paymentType    = "SERVICE";

 

  // print_r($receiver);

  $receiverList = new ReceiverList($receiver);

 

 

Definition of the main parameters. Return URL and cancel URL are mandatory even if they will not be used.

 

Receivers are the recipient of the payment.

 

 

 

 

  // print_r($receiverList);

  $payRequest = new PayRequest(new RequestEnvelope("en_US"), $actionType, $cancelUrl, $currency, $receiverList, $returnUrl);

  $payRequest->preapprovalKey = $preappouved[$i_customer]['preapproval_key'];

  $payRequest->ipnNotificationUrl = IPN_NOTIFICATION_URL;

  $payRequest->senderEmail  = $preappouved[$i_customer]['senderEmail'];

 

  $service = new AdaptivePaymentsService(Configuration::getAcctAndConfig());

  try {

    /* wrap API method calls on the service object with a try catch */

    $response = $service->Pay($payRequest);

  } catch(Exception $ex) {

    require_once '../Common/Error.php';

  }

 

Sending the pay request.

 

  $ack = strtoupper($response->responseEnvelope->ack);

 

  if($ack != "SUCCESS") {

    echo "ERROR\n";

    send_info_mail("[error] PayPal periodic payment", "Error during automatic payment with PayPal for i_customer $i_customer \n\n-------------\n\n". print_r($response, TRUE) , $payKey );

    return FALSE;

  } else {

    // Update the database with the day of payment.

    $payKey = $response->payKey;

    if(($response->paymentExecStatus == "COMPLETED" )) {

      send_info_mail("PayPal periodic payment / status: paid ", "i_customer: $i_customer \n\nDATA:\n " . print_r($response, TRUE) , $payKey );

      return $payKey;

    } else {

      send_info_mail("[unknown] PayPal periodic payment / status: unknown", "Unknown status of payment with PayPal for i_customer $i_customer \n\n-------------\n\n". print_r($response, TRUE) , $payKey );

    }

  }

  return FALSE;

}

 

Getting the answer from PayPal.

 

We send email for success or errors.

 

The function return false if the transaction failed or the pay key if succeed.

 

 

 

function execute_pb_payment( $i_customer, $amount, $transaction_id ){

  global $ServiceCustomer;

 

  $MakeCustomerTransactionRequest = array(

    'i_customer'            => $i_customer,

    'visible_comment'       => 'paiement paypal',

    'internal_comment'      => 'paiement paypal',

    'action'                => 'Manual payment',

    'amount'                => $amount,

    'suppress_notification' => 0,

    'transaction_id'        => $transaction_id,

    'h323_conf_id'          => ''

  );

  try {

    $MakeCustomerTransactionResponse = $ServiceCustomer->make_transaction($MakeCustomerTransactionRequest);

  } catch (SoapFault $fault) {

    echo "Failed to update porta-billing\n";

    send_info_mail("[error] PayPal periodic payment", "Error during payment on porta-billing \n ".$fault, $transaction_id, true );

    return false;

  }

  send_info_mail("[done] PayPal periodic payment : conpleted", "Payment was entered in porta-billing. \nRequest : \n\n ------------ \n\n".print_r($MakeCustomerTransactionRequest, TRUE), $transaction_id, true );

  return true;

}

 

Function for executing the payments on porta-billing with SOAP.

 

We send email on success or errors.

 

 

function update_last_payment_record ( $i_periodical_payment ) {

  global $mysqli_master;

  echo "update_last_payment_record\n";

  if ( isset( $i_periodical_payment ) && preg_match( '/^[0-9]+$/', $i_periodical_payment ) ){

    $query = "UPDATE Periodical_Payments SET last_payment = CURDATE() WHERE i_periodical_payment = ?";

    $stmt = $mysqli_master->prepare($query);

    if ( false===$stmt ) {

      echo $mysqli_master->error;

    }

    $stmt->bind_param('i', $i_periodical_payment );

    $stmt->execute();

    $stmt->close();

  }

}

 

The function for updating the last payment record in the Periodical_Payments in the master database.

 

function send_info_mail( $subject, $body, $transaction_id, $answer = false ){

 

  $mail_From    = "PayPal_IPN@switzernet.com";

  $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      = "nicolas.bondier@switzernet.com.test-google-a.com";

  $mail_Header = "";

  $mail_Header .= 'From: ' . $mail_From                                                           . "\r\n";

  $mail_Header .= 'Reply-To: '.$mail_To                                                           . "\r\n";

  if ( $answer == false ){

    $mail_Header .= 'Message-Id: <'$transaction_id . '@ipn.switzernet.com>'                   . "\r\n";

  } else {

    $mail_Header .= 'Message-Id: <'$transaction_id . '.' . time() . '@ipn.switzernet.com>' . "\r\n";

    $mail_Header .= 'References: <' . $transaction_id . '@ipn.switzernet.com>'                   . "\r\n";

    $mail_Header .= 'In-Reply-To: <'. $transaction_id . '@ipn.switzernet.com>'                   . "\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);

 

}

 

?>

 

The function for sending information emails.

 

Transaction id is used for the messages ids and keeping emails in threads.

 

 


Links

Ce document : http://switzernet.com/3/public/141030-paypal-adaptive/

Switzernet customer interface : https://account.switzernet.com/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

*                  *                  *

Copyright © 2014 by Switzernet