Billing

Read the article Paypal to learn how to configure your site for payments with Paypal in test mode and in production mode.

NOTE: This article is based on the interface with PayPal. If you use Payline, or another payment system, the principles are identical and your code will be very similar with just a few adaptations for the API of payment system.

You have validated you configuration in test mode with the donation form Donate. You want to change the logo which is displayed by Paypal and give in more details to the buyer.

Add an image file, a JPG or a PNG, in the directory logos. Name it sitepaypal.jpg or sitepaypal.png. This image will appear at the top left of the payment page. It has a maximum size of 750x90 px.

Edit the file strings.inc in the folder includes. Add the translation of payment:name and payment:desc in English:

        'payment:name'          => 'Payment to ' . $sitename,
        'payment:desc'          => 'Subscription 1 year',

And in French:

        'payment:name'          => 'Paiement à ' . $sitename,
        'payment:desc'          => 'Abonnement 1 année',

Edit the function paypalcheckout in the file paypalcheckout.php of the folder actions.

Redefine $name and add $desc:

  1.     $name=translate('payment:name', $lang);
  2.     $desc=translate('payment:desc', $lang);

Redefine $hdrimg:

  1.     $hdrimg=$base_url . '/logos/sitepaypal.png';

Edit the parameters HDRIMG, L_PAYMENTREQUEST_0_NAME0 and L_PAYMENTREQUEST_0_DESC0 passed by the array $params to the function paypal_setexpresscheckout:

  1.         'L_PAYMENTREQUEST_0_NAME0'          => $name,
  2.         'L_PAYMENTREQUEST_0_DESC0'          => $desc,
  1.         'HDRIMG'                            => $hdrimg,

Validate a complete payment by the site with the donation form. Check that the new logo is displayed at the top of the payment page by Paypal.

Create a table in the database called payment:

CREATE TABLE `izend_payment` (
  `payment_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` INT(10) UNSIGNED NOT NULL,
  `paypal_id` CHAR(17) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
  `payed` datetime NOT NULL,
  `amount` DECIMAL(7,2) UNSIGNED NOT NULL,
  `vat` DECIMAL(7,2) UNSIGNED NOT NULL,
  `fee` DECIMAL(7,2) UNSIGNED NOT NULL,
  `currency` enum('EUR','USD','GBP') NOT NULL DEFAULT 'EUR',
  `billing_name` VARCHAR(100) NOT NULL,
  `billing_address` VARCHAR(1000) NOT NULL,
  PRIMARY KEY (`payment_id`)
) DEFAULT CHARSET=utf8;

NOTE: Adapt the prefix of the table to your configuration. If you accept only one currency, you can drop the field currency.

Create the file payment.inc in the folder models with the following content:

  1. function payment_vat_rate() {
  2.     return 0.20;
  3. }

payment_vat_rate returns the VAT rate applicable to a payment. The code of this function can take into account the type of product which is sold and deal with the case of export sales.

  1. function payment_log($user_id, $transactionid, $amount, $vat, $fee, $currency, $billing_name, $billing_address) {
  2.     if (!is_numeric($user_id)) {
  3.         return false;
  4.     }
  5.  
  6.     $sqlpaymentid=db_sql_arg($transactionid, false);
  7.     $sqlcurrency=db_sql_arg($currency, false);
  8.     $sqlbillingname=db_sql_arg($billing_name, true);
  9.     $sqlbillingaddress=db_sql_arg($billing_address, true);
  10.  
  11.     $tabpayment=db_prefix_table('payment');
  12.  
  13.     $sql="INSERT $tabpayment (user_id, paypal_id, payed, amount, vat, fee, currency, billing_name, billing_address) VALUES ($user_id, $sqlpaymentid, NOW(), $amount, $vat, $fee, $sqlcurrency, $sqlbillingname, $sqlbillingaddress)";
  14.  
  15.     $r = db_insert($sql);
  16.  
  17.     if (!$r) {
  18.         return false;
  19.     }
  20.  
  21.     $payment_id = db_insert_id();
  22.  
  23.     return $payment_id;
  24. }

payment_log saves the details of a payment in the database.

  1. function payment_detail($payment_id) {
  2.     if (!is_numeric($payment_id)) {
  3.         return false;
  4.     }
  5.  
  6.     $tabpayment=db_prefix_table('payment');
  7.  
  8.     $sql="SELECT user_id AS payment_user_id, UNIX_TIMESTAMP(payed) AS payment_payed, amount AS payment_amount, vat AS payment_vat, fee AS payment_fee, currency AS payment_currency, billing_name AS payment_billing_name, billing_address AS payment_billing_address FROM $tabpayment WHERE payment_id=$payment_id";
  9.  
  10.     $r = db_query($sql);
  11.  
  12.     return $r ? $r[0] : false;
  13. }

payment_detail returns all the information saved in the database about a payment.

  1. function user_get_payments($user_id) {
  2.     if (!is_numeric($user_id)) {
  3.         return false;
  4.     }
  5.  
  6.     $tabpayment=db_prefix_table('payment');
  7.  
  8.     $sql="SELECT payment_id AS payment_id, paypal_id AS payment_paypal_id, UNIX_TIMESTAMP(payed) as payment_payed, amount AS payment_amount, vat AS payment_vat, fee AS payment_fee, currency AS payment_currency, billing_name AS payment_billing_name, billing_address AS payment_billing_address FROM $tabpayment WHERE user_id=$user_id ORDER BY payed DESC";
  9.  
  10.     $r = db_query($sql);
  11.  
  12.     return $r;
  13. }

user_get_payments returns all the information about all the payments made by a user.

Edit the function paymentaccepted in the file paymentaccepted.php of the folder actions.

  1. require_once 'models/payment.inc';

Loads the code of the function payment_log.

  1. function paymentaccepted($lang, $amount, $currency, $tax, $transactionid, $fee, $context) {

Adds the arguments $tax, $transactioni and $fee to the function paymentaccepted.

  1.     $user_id = $context['user_id'];
  2.     $billing_name = $context['billing_name'];
  3.     $billing_address = $context['billing_address'];
  4.    
  5.     $r = payment_log($user_id, $transactionid, $amount, $tax, $fee, $currency, $billing_name, $billing_address);
  6.    
  7.     if (!$r) {
  8.         return run('error/internalerror', $lang);
  9.     }

Extracts the information on the identity of the buyer from the context of the operation. Records the payment in the database.

  1.     require_once 'serveripaddress.php';
  2.     require_once 'emailme.php';
  3.    
  4.     global $sitename;
  5.    
  6.     $ip=server_ip_address();
  7.     $timestamp=strftime('%Y-%m-%d %H:%M:%S', time());
  8.     $subject = 'payment' . '@' . $sitename;
  9.     $msg = $ip . ' ' . $timestamp . ' ' . $user_id . ' ' . $transactionid . ' ' . $amount . ' ' . $currency;
  10.     @emailme($subject, $msg);

Sends a notification about the payment by email to the administrator of the website.

Edit the function paypalreturn in the file paypalreturn.php of the folder actions and add the parameters $taxamt, $transactionid and $feeamt to the call of the function paymentaccepted:

  1.         $output = paymentaccepted($lang, $amt, $currencycode, $taxamt, $transactionid, $feeamt, $context);
Test

In order to test the recording of a payment, add passing the information about the buyer to the call of the function paypalcheckout in the block donateme :

  1.             $user_id=1;
  2.  
  3.             $billing_name='Jean Dupont';
  4.             $billing_address="Champ de Mars\n5 avenue Anatole France\n75007 Paris";
  5.  
  6.             $context=compact('user_id', 'billing_name', 'billing_address');
  7.  
  8.             paypalcheckout($lang, $amount, $currency, 0, $context);

Do a payment in test mode with the donation form Donate and check the content of the table payment in the database.

IMPORTANT: Block the access to the donation form by editing the file aliases.inc in the folder includes.

Create the file invoice.phtml in the folder layouts with the following content:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <?php if ($lang): ?>
  5. <meta http-equiv="content-type" content="text/html; charset=utf-8" lang="<?php echo $lang; ?>" />
  6. <?php else: ?>
  7. <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  8. <?php endif; ?>
  9. <meta name="generator" content="iZend" />
  10. <meta name="robots" content="noindex, nofollow" />
  11. <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
  12. <link href="<?php echo $base_path; ?>/css/zero.css" rel="stylesheet" type="text/css" media="screen" />
  13. <link href="<?php echo $base_path; ?>/css/invoice.css" rel="stylesheet" type="text/css" media="all" />
  14. <?php if ($lang): ?>
  15. <link href="<?php echo $base_path; ?>/css/<?php echo $lang; ?>.css" rel="stylesheet" type="text/css" media="all" />
  16. <?php endif; ?>
  17. <?php if (true): ?>
  18. <script type="text/javascript" src="<?php echo $base_path; ?>/js/jquery.js"></script>
  19. <?php endif; ?>
  20. <title><?php echo $title; ?></title>
  21. </head>
  22. <body>
  23. <?php echo $content; ?>
  24. </body>
  25. </html>

Create the version in English of the file invoice.phtml in the folder views/en with the following content:

  1. <?php require_once 'dateen.php'; ?>
  2. <div id="header">
  3. <p><img src="<?php echo $base_path; ?>/logos/sitelogo.png" alt="<?php echo $sitename; ?>" title="" /></p>
  4. <table>
  5. <tbody>
  6. <tr><td id="buyer" colspan="2"><?php echo $billing_name; ?><br /><?php echo nl2br($billing_address); ?></td></tr>
  7. <tr><td id="seller">Company name<br />Address of head office<br />12345 Town<br /><br />ID number<br />VAT number</td><td id="date"><?php echo date('m/d/Y', $now); ?></td></tr>
  8. </tbody>
  9. </table>
  10. </div>
  11. <p>Invoice <?php echo $number; ?> paid <?php echo longdate_en($date); ?> at <?php echo date('H:i:s', $date); ?></p>
  12. <div id="billing">
  13. <table>
  14. <tbody>
  15. <tr><th><?php echo $payment_desc; ?></th><td><?php echo number_format($ht, 2, '.', ' '); ?>&nbsp;<?php echo $currency; ?></td></tr>
  16. <?php if ($vat): ?>
  17. <tr><th>VAT <?php echo preg_replace('/[,.]?0*$/', '' , number_format($vat_rate, 2, '.', '')); ?>%</th><td><?php echo number_format($vat, 2, '.', ' '); ?>&nbsp;<?php echo $currency; ?></td></tr>
  18. <?php endif; ?>
  19. <tr><th>Total</th><td><?php echo number_format($total, 2, '.', ' '); ?>&nbsp;<?php echo $currency; ?></td></tr>
  20. </tbody>
  21. </table>
  22. </div>
  23. <div id="footer">
  24. <p>Consult your account on <a href="<?php echo $base_url; ?>"><i><?php echo $sitename; ?></i></a>.</p>
  25. </div>
  26. <?php if (true): ?>
  27. <script type="text/javascript">
  28. //<![CDATA[
  29. $('#footer').append('<p class="link">To print the invoice, <a href="javascript:window.print()" title="Print your bill on paper">click here</a>.</p>\n');
  30. //]]>
  31. </script>
  32. <?php endif; ?>

Create the version in French of the file invoice.phtml in the folder views/fr with the following content:

  1. <?php require_once 'datefr.php'; ?>
  2. <div id="header">
  3. <p><img src="<?php echo $base_path; ?>/logos/sitelogo.png" alt="<?php echo $sitename; ?>" title="" /></p>
  4. <table>
  5. <tbody>
  6. <tr><td id="buyer" colspan="2"><?php echo $billing_name; ?><br /><?php echo nl2br($billing_address); ?></td></tr>
  7. <tr><td id="seller">Dénomination sociale<br />Adresse du siège<br />12345 Ville<br /><br />N° d'identification<br />N° de TVA</td><td id="date"><?php echo date('d-m-Y', $now); ?></td></tr>
  8. </tbody>
  9. </table>
  10. </div>
  11. <p>Facture <?php echo $number; ?> payée le <?php echo longdate_fr($date); ?> à <?php echo date('H:i:s', $date); ?></p>
  12. <div id="billing">
  13. <table>
  14. <tbody>
  15. <tr><th><?php echo $payment_desc; ?></th><td><?php echo number_format($ht, 2, ',', ' '); ?>&nbsp;<?php echo $currency; ?></td></tr>
  16. <?php if ($vat): ?>
  17. <tr><th>TVA <?php echo preg_replace('/[,.]?0*$/', '' , number_format($vat_rate, 2, ',', '')); ?>%</th><td><?php echo number_format($vat, 2, ',', ' '); ?>&nbsp;<?php echo $currency; ?></td></tr>
  18. <?php endif; ?>
  19. <tr><th>Total</th><td><?php echo number_format($total, 2, ',', ' '); ?>&nbsp;<?php echo $currency; ?></td></tr>
  20. </tbody>
  21. </table>
  22. </div>
  23. <div id="footer">
  24. <p>Consultez votre compte sur <a href="<?php echo $base_url; ?>"><i><?php echo $sitename; ?></i></a>.</p>
  25. </div>
  26. <?php if (true): ?>
  27. <script type="text/javascript">
  28. //<![CDATA[
  29. $('#footer').append('<p class="link">Pour imprimer la facture, <a href="javascript:window.print()" title="Imprimez votre facture sur papier">cliquez ici</a>.</p>\n');
  30. //]]>
  31. </script>
  32. <?php endif; ?>

Create the file invoice.css in the folder css with the following content:

  1. a:link, a:visited {color:grey;text-decoration:none;}
  2. a:hover {color:black;text-decoration:none;}
  3.  
  4. body {color:black;line-height:1.5;font-family:Verdana, sans-serif;font-size:12pt;margin:5%;}
  5.  
  6. #header {margin-bottom:2em;}
  7. #header table {border-spacing:0;}
  8. #header td {padding:1em 0;}
  9. #header #buyer {text-align:right;}
  10. #header #seller {text-align:left;padding-right:15em;}
  11. #header #date {text-align:right;vertical-align:bottom;}
  12.  
  13. #billing table {border-spacing:0;}
  14. #billing td {text-align:right;padding:0.25em 0;}
  15. #billing th {text-align:left;padding-right:3em;font-weight:normal;}
  16.  
  17. #footer {margin-top:2em;}
  18.  
  19. @media print {
  20.     .link {display:none;}
  21. }

Create the file invoice.php in the folder actions with the following content:

  1. require_once 'userhasrole.php';
  2. require_once 'userprofile.php';
  3. require_once 'models/payment.inc';
  4.  
  5. function invoice($lang, $arglist=false) {
  6.     if (!(user_has_role('client') or user_has_role('administrator'))) {
  7.         return run('error/unauthorized', $lang);
  8.     }
  9.  
  10.     $payment_id=false;
  11.  
  12.     if (is_array($arglist)) {
  13.         if (isset($arglist[0])) {
  14.             $payment_id=$arglist[0];
  15.         }
  16.     }
  17.  
  18.     if (!$payment_id or !is_numeric($payment_id)) {
  19.         return run('error/badrequest', $lang);
  20.     }
  21.  
  22.     $r = payment_detail($payment_id);
  23.  
  24.     if (!$r) {
  25.         return run('error/notfound', $lang);
  26.     }
  27.     extract($r);    /* payment_user_id payment_payed payment_amount payment_fee payment_vat payment_currency payment_billing_name payment_billing_address */
  28.  
  29.     $user_id=user_profile('id');
  30.  
  31.     if ($user_id != $payment_user_id and !user_has_role('administrator')) {
  32.         return run('error/notfound', $lang);
  33.     }
  34.  
  35.     $billing_name=$payment_billing_name;
  36.     $billing_address=$payment_billing_address;
  37.  
  38.     $total=$payment_amount;
  39.     $vat=$payment_vat;
  40.     $ht=$payment_amount-$payment_vat;
  41.     $vat_rate=($vat/$ht) * 100;
  42.     $currency=$payment_currency;
  43.     $date=$payment_payed;
  44.  
  45.     $payment_desc=translate('payment:desc', $lang);
  46.  
  47.     $number=date('Y', $date) . '-' . $payment_id;
  48.  
  49.     $now=time();
  50.  
  51.     $title=translate('invoice:title', $lang);
  52.  
  53.     $content = view('invoice', $lang, compact('now', 'billing_name', 'billing_address', 'number', 'date', 'ht', 'vat', 'total', 'currency', 'vat_rate', 'payment_desc'));
  54.  
  55.     $output = layout('invoice', compact('lang', 'title', 'content'));
  56.  
  57.     return $output;
  58. }

In the file aliases.inc of the folder includes, associate the action invoice to the URL /en/facture and to the URL /fr/invoice:

        'invoice'                   => 'invoice',
        'facture'                   => 'invoice',

Connect as an administrator and enter the addresse /en/invoice/1 after the domain name of the site to display the invoice 1.

Comments

To add a comment, click here.