1
6

Facturation

Lisez l'article Paypal pour apprendre comment configurer votre site pour des paiements avec Paypal en mode test et mode production.

NOTE : Cet article est basée sur l'interface avec PayPal. Si vous utilisez Payline, ou un autre système de paiement, les principes sont identiques et votre code sera très similaire avec quelques adaptations pour l'API du système de paiement.

Vous avez validé votre configuration en mode test avec le formulaire de donation Faire un don. Vous voulez changer le logo qui est affiché par Paypal et spécifiez plus de détails à l'acheteur.

Ajoutez un fichier image, un JPG ou un PNG, dans le répertoire logos. Appelez-le sitepaypal.jpg ou sitepaypal.png. Cette image apparaîtra en haut à gauche de la page du paiement. Elle a une taille maximum de 750x90 px.

Éditez le fichier strings.inc dans le dossier includes. Ajoutez la traduction de payment:name et payment:desc en français :

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

Et en anglais :

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

Éditez la fonction paypalcheckout dans le fichier paypalcheckout.php du dossier actions.

Redéfinissez $name et ajoutez $desc :

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

Redéfinissez $hdrimg :

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

Éditez les paramètres HDRIMG, L_PAYMENTREQUEST_0_NAME0 et L_PAYMENTREQUEST_0_DESC0 passés par le tableau $params à la fonction paypal_setexpresscheckout :

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

Validez un paiement complet par le site à l'aide du formulaire de don. Vérifiez que le nouveau logo est bien affiché en haut de la page du paiement par Paypal.

Créez une table dans la base de données appelée 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 : Adaptez le préfixe de la table à votre configuration. Si vous n'acceptez qu'une seule monnaie, vous pouvez supprimer le champ currency.

Créez le fichier payment.inc dans le dossier models avec le contenu suivant :

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

payment_vat_rate retourne le taux de TVA appliqué à un paiement. Le code de cette fonction peut prendre en compte le type de produit vendu et gérer les cas de vente à l'export.

  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 enregistre les détails d'un paiement dans la base de données.

  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 retourne toutes les informations enregistrées dans la base de données à propos d'un paiement.

  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 retourne toutes les informations sur tous les paiements effectués par un utilisateur.

Éditez la fonction paymentaccepted dans le fichier paymentaccepted.php du dossier actions.

  1. require_once 'models/payment.inc';

Charge le code de la fonction payment_log.

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

Ajoute les arguments $tax, $transactionid et $fee à la fonction 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.     }

Extrait les informations sur l'identité de l'acheteur du contexte de l'opération. Enregistre le paiement dans la base de données.

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

Envoie une notification du paiement par email à l'administrateur du site.

Éditez la fonction paypalreturn dans le fichier paypalreturn.php du dossier actions et ajoutez les paramètres $taxamt, $transactionid et $feeamt à l'appel de la fonction paymentaccepted :

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

Afin de tester l'enregistrement d'un paiement, ajoutez le passage des informations sur l'acheteur à l'appel de la fonction paypalcheckout dans le bloc 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);

Effectuez un paiement en mode test avec le formulaire de donation Faire un don et vérifiez le contenu de la table payment dans la base de données.

IMPORTANT : Bloquez l'accès au formulaire de donation en éditant le fichier aliases.inc dans le dossier includes.

Facture

Créez le fichier invoice.phtml dans le dossier layouts avec le contenu suivant :

  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>

Créez la version en français du fichier invoice.phtml dans le dossier views/fr avec le contenu suivant :

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

Créez la version en anglais du fichier invoice.phtml dans le dossier views/en avec le contenu suivant :

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

Créez le fichier invoice.css dans le dossier css avec le contenu suivant :

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

Créez le fichier invoice.php dans le dossier actions avec le contenu suivant :

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

Dans le fichier aliases.inc du dossier includes, associez l'action invoice à l'URL /fr/facture et à l'URL /en/invoice :

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

Connectez-vous en tant qu'administrateur et entrez l'adresse /fr/facture/1 à la suite du nom de domaine du site pour afficher la facture 1.

Commentaires

Pour ajouter un commentaire, cliquez ici.