[26/09/2024] MAJ du module PayBox en 1.2.5, pour contrainte 3DSv2

This commit is contained in:
2024-09-26 15:54:12 +02:00
parent e288ca861d
commit 0359d96baf
27 changed files with 2860 additions and 2420 deletions

View File

@@ -62,7 +62,8 @@
"ramsey/array_column": "~1.1",
"propel/propel": "dev-thelia-2.3",
"commerceguys/addressing": "0.8.*",
"thelia/paypal-module": "~3.0.0"
"thelia/paypal-module": "~3.0.0",
"giggsey/libphonenumber-for-php": "^8.1.3"
},
"require-dev": {
"fzaninotto/faker": "1.5.*",

136
composer.lock generated
View File

@@ -1,10 +1,10 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "8fbc68f5bab568a5ff0999a67a6fef4f",
"content-hash": "9adcc003d8cd7a382d5fedd229b5e860",
"packages": [
{
"name": "commerceguys/addressing",
@@ -349,17 +349,134 @@
"abandoned": "tecnickcom/tcpdf",
"time": "2013-09-12T17:00:40+00:00"
},
{
"name": "giggsey/libphonenumber-for-php",
"version": "8.12.4",
"source": {
"type": "git",
"url": "https://github.com/giggsey/libphonenumber-for-php.git",
"reference": "cb79970730aacaedb74c8288214a5576572fa7b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/cb79970730aacaedb74c8288214a5576572fa7b0",
"reference": "cb79970730aacaedb74c8288214a5576572fa7b0",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"giggsey/locale": "^1.7",
"php": ">=5.3.2"
},
"require-dev": {
"pear/pear-core-minimal": "^1.9",
"pear/pear_exception": "^1.0",
"pear/versioncontrol_git": "^0.5",
"phing/phing": "^2.7",
"php-coveralls/php-coveralls": "^1.0|^2.0",
"phpunit/phpunit": "^4.8.36|^5.0",
"symfony/console": "^2.8|^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "8.x-dev"
}
},
"autoload": {
"psr-4": {
"libphonenumber\\": "src/"
},
"exclude-from-classmap": [
"/src/data/",
"/src/carrier/data/",
"/src/geocoding/data/",
"/src/timezone/data/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Joshua Gigg",
"email": "giggsey@gmail.com",
"homepage": "https://giggsey.com/"
}
],
"description": "PHP Port of Google's libphonenumber",
"homepage": "https://github.com/giggsey/libphonenumber-for-php",
"keywords": [
"geocoding",
"geolocation",
"libphonenumber",
"mobile",
"phonenumber",
"validation"
],
"time": "2020-05-19T11:20:54+00:00"
},
{
"name": "giggsey/locale",
"version": "1.9",
"source": {
"type": "git",
"url": "https://github.com/giggsey/Locale.git",
"reference": "b07f1eace8072ccc61445ad8fbd493ff9d783043"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/giggsey/Locale/zipball/b07f1eace8072ccc61445ad8fbd493ff9d783043",
"reference": "b07f1eace8072ccc61445ad8fbd493ff9d783043",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"pear/pear-core-minimal": "^1.9",
"pear/pear_exception": "^1.0",
"pear/versioncontrol_git": "^0.5",
"phing/phing": "~2.7",
"php-coveralls/php-coveralls": "^1.0|^2.0",
"phpunit/phpunit": "^4.8|^5.0",
"symfony/console": "^2.8|^3.0|^4.0",
"symfony/filesystem": "^2.8|^3.0|^4.0",
"symfony/finder": "^2.8|^3.0|^4.0",
"symfony/process": "^2.8|^3.0|^4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Giggsey\\Locale\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joshua Gigg",
"email": "giggsey@gmail.com",
"homepage": "http://giggsey.com/"
}
],
"description": "Locale functions required by libphonenumber-for-php",
"time": "2020-07-07T11:16:24+00:00"
},
{
"name": "imagine/imagine",
"version": "v0.6.3",
"source": {
"type": "git",
"url": "https://github.com/avalanche123/Imagine.git",
"url": "https://github.com/php-imagine/Imagine.git",
"reference": "149041d2a1b517107bfe270ca2b1a17aa341715d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/avalanche123/Imagine/zipball/149041d2a1b517107bfe270ca2b1a17aa341715d",
"url": "https://api.github.com/repos/php-imagine/Imagine/zipball/149041d2a1b517107bfe270ca2b1a17aa341715d",
"reference": "149041d2a1b517107bfe270ca2b1a17aa341715d",
"shasum": ""
},
@@ -714,6 +831,7 @@
"php",
"stylesheet"
],
"abandoned": true,
"time": "2015-12-30T05:47:36+00:00"
},
{
@@ -811,6 +929,7 @@
"rest",
"sdk"
],
"abandoned": true,
"time": "2016-04-22T03:29:29+00:00"
},
{
@@ -1001,6 +1120,7 @@
"array_column",
"column"
],
"abandoned": "it-for-free/array_column",
"time": "2015-03-20T22:07:39+00:00"
},
{
@@ -1159,6 +1279,7 @@
"keywords": [
"stack"
],
"abandoned": true,
"time": "2014-11-23T20:37:11+00:00"
},
{
@@ -1212,6 +1333,7 @@
"mail",
"mailer"
],
"abandoned": "symfony/mailer",
"time": "2015-06-06T14:19:39+00:00"
},
{
@@ -1378,6 +1500,7 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
"abandoned": true,
"time": "2016-01-03T15:33:41+00:00"
},
{
@@ -1545,6 +1668,7 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"abandoned": "symfony/error-handler",
"time": "2016-01-13T10:28:07+00:00"
},
{
@@ -2916,6 +3040,7 @@
],
"description": "Symfony Security Component",
"homepage": "https://symfony.com",
"abandoned": true,
"time": "2016-01-14T09:10:32+00:00"
},
{
@@ -4450,5 +4575,6 @@
"platform": {
"php": ">=5.4"
},
"platform-dev": []
"platform-dev": [],
"plugin-api-version": "1.1.0"
}

BIN
composer.phar Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
name: "Auto Release"
on:
push:
branches: [ master, main ]
jobs:
release:
uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="module_configuration.html" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
</dwsync>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="clef-publique-paybox.pem" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
<file name="config.xml" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
<file name="iso4217.xml" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
<file name="module.xml" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
<file name="routing.xml" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
</dwsync>

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module>
<fullnamespace>Paybox\Paybox</fullnamespace>
<descriptive locale="en_US">
<title>Pay with credit card using Paybox</title>
</descriptive>
<descriptive locale="fr_FR">
<title>Paiement en carte bancaire avec Paybox</title>
</descriptive>
<version>1.0.0</version>
<author>
<name>Franck Allimant</name>
<email>franck@cqfdev.fr</email>
</author>
<type>payment</type>
<thelia>2.1.0</thelia>
<stability>prod</stability>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<module>
<fullnamespace>Paybox\Paybox</fullnamespace>
<descriptive locale="en_US">
<title>Pay with credit card using Paybox</title>
</descriptive>
<descriptive locale="fr_FR">
<title>Paiement en carte bancaire avec Paybox</title>
</descriptive>
<version>1.2.5</version>
<author>
<name>Franck Allimant</name>
<email>franck@cqfdev.fr</email>
</author>
<type>payment</type>
<thelia>2.1.0</thelia>
<stability>prod</stability>
</module>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="ConfigurationController.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
<file name="PaymentController.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
</dwsync>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="SendConfirmationEmail.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="ConfigurationForm.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="en_US.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="fr_FR.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -1,35 +1,35 @@
<?php
return array(
'<ol>
<li>
L\'interface de génération de la clé secrète d\'authentification se trouve dans l\'onglet "Informations" du Back Office Commerçant de Paybox, en bas de la page.
</li>
<li>
Le champ "Phrase de passe" peut être renseigné avec une phrase, un mot de passe, ou tout autre texte.
</li>
<li>
L\'affichage par défaut du champ "Phrase de passe" est caché, les caractères apparaissent comme un champ "mot de passe". Il est possible de choisir d\'afficher cette phrase de passe en décochant la case "Cacher".
</li>
<?php
return array(
'<ol>
<li>
L\'interface de génération de la clé secrète d\'authentification se trouve dans l\'onglet "Informations" du Back Office Commerçant de Paybox, en bas de la page.
</li>
<li>
Le champ "Phrase de passe" peut être renseigné avec une phrase, un mot de passe, ou tout autre texte.
</li>
<li>
L\'affichage par défaut du champ "Phrase de passe" est caché, les caractères apparaissent comme un champ "mot de passe". Il est possible de choisir d\'afficher cette phrase de passe en décochant la case "Cacher".
</li>
<li>
Les champs "Complexité" et "Force" sont mis à jour automatiquement lorsque la phrase de passe est saisie. Ces champs permettent de définir des règles d\'acceptation minimales de la phrase de passe. Les règles fixées actuellement demandent une phrase de passe d\'au moins 15 caractères de long et d\'une force de 90%. Le bouton "VALIDER" restera grisé tant que ces limitations ne sont pas respectées.
</li>
<li>
Le bouton "Générer une clé" permet de calculer la clé d\'authentification à partir de la phrase de passe saisie. Ce calcul est une méthode standard assurant le caractère aléatoire de la clé et renforçant sa robustesse. Cette méthode de calcul étant fixe, il est possible à tout moment de retrouver sa clé en retapant la même phrase de passe et en relançant le calcul.<br />
Attention, il est possible que le calcul de la clé prenne quelques secondes, selon le navigateur Internet utilisé et la puissance de l\'ordinateur. Au cours du calcul, il se peut que votre navigateur demande s\'il faut "arrêter l\'exécution de ce script". Il faut répondre "Non" à cette alerte, et patienter jusqu\'à la fin du calcul.

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="en_US.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="fr_FR.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="fr_FR.php" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -1,6 +1,6 @@
<?php
return array(
<?php
return array(
'Unsupported field type \'%type\' in form-field-template.html' => 'Le type de champ \'%type\' n\'est pas pris en charge par form-field-template.html',
'Use Ctrl+click to select (or deselect) more that one item' => 'Utilisez Ctrl+clic pour sélectionner ou désélectionner un élément',
);

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="en.html" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="en.txt" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="fr.html" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="fr.txt" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="notification-en.html" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="notification-en.txt" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="notification-fr.html" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="notification-fr.txt" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -12,6 +12,7 @@ return array(
'Failed to open %file, please check Paybox configuration' => 'Failed to open %file, please check Paybox configuration',
'Identifiant interne' => 'Internal identifier',
'Identifiant interne, tel que fourni par Paybox' => 'Internal identifier, provided by Paybox',
'Invalid phone number %num for country %country' => 'Invalid phone number %num for country %country',
'Le fichier de log est vide.' => 'The log file is empty.',
'Le fichier de log n\'a pas été trouvé.' => 'The log file could not be found.',
'Maximum order total' => 'Maximum order total',
@@ -32,6 +33,7 @@ return array(
'Paybox configuration' => 'Paybox configuration',
'Paybox platform request processing terminated.' => 'Paybox platform request processing terminated.',
'Paybox platform request received.' => 'Paybox platform request received.',
'Please enter a valid phone number in your invoice address (error is : %err)' => 'Please enter a valid phone number in your invoice address (error is : %err)',
'Production' => 'Production',
'Request parameters signature verification failed.' => 'Request parameters signature verification failed.',
'Test' => 'Test',

View File

@@ -12,6 +12,7 @@ return array(
'Failed to open %file, please check Paybox configuration' => 'Le fichier %file est inaccessible, merci de vérifier la configuration Paybox',
'Identifiant interne' => 'Identifiant interne',
'Identifiant interne, tel que fourni par Paybox' => 'Identifiant interne, tel que fourni par Paybox',
'Invalid phone number %num for country %country' => 'Le numéro de téléphone %num est invalide pour le pays %country',
'Le fichier de log est vide.' => 'Le fichier de log est vide.',
'Le fichier de log n\'a pas été trouvé.' => 'Le fichier de log n\'a pas été trouvé.',
'Maximum order total' => 'Montant de commande maximum',
@@ -32,6 +33,7 @@ return array(
'Paybox configuration' => 'Configuration Paybox',
'Paybox platform request processing terminated.' => 'Traitement de la requête Paybox terminé.',
'Paybox platform request received.' => 'Réception d\'une requête de la plate-form Paybox',
'Please enter a valid phone number in your invoice address (error is : %err)' => 'Merci d\'entrer un numero de téléphone mobile valide dans votre adresse de facturation (détail de l\'erreur : %err)',
'Production' => 'Production',
'Request parameters signature verification failed.' => 'La vérification de la signature de la requête a échoué.',
'Test' => 'Test',

View File

@@ -1,340 +1,420 @@
<?php
/*************************************************************************************/
/* */
/* Thelia 2 Paybox payment module */
/* */
/* Copyright (c) CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/*************************************************************************************/
namespace Paybox;
use Propel\Runtime\Connection\ConnectionInterface;
use Thelia\Core\HttpFoundation\Response;
use Thelia\Core\Translation\Translator;
use Thelia\Log\Tlog;
use Thelia\Model\Message;
use Thelia\Model\MessageQuery;
use Thelia\Model\ModuleImageQuery;
use Thelia\Model\Order;
use Thelia\Module\AbstractPaymentModule;
/**
* Paybox payment module
*
* @author Franck Allimant <franck@cqfdev.fr>
*/
class Paybox extends AbstractPaymentModule
{
/** The module domain for internationalisation */
const MODULE_DOMAIN = "paybox";
/** The module domain for internationalisation */
const MODULE_CODE = "Paybox";
/** The confirmation message identifier */
const CONFIRMATION_MESSAGE_NAME = 'paybox_payment_confirmation';
// Liste des variables retournées par paybox
const PARAMETRES_RETOUR = 'montant:M;ref:R;auto:A;trans:T;erreur:E;sign:K';
/** The notification of payment confirmation */
const NOTIFICATION_MESSAGE_NAME = 'paybox_payment_status_notification';
/**
* @inheritdoc
*/
public function postActivation(ConnectionInterface $con = null)
{
// Create payment confirmation message from templates, if not already defined
$email_templates_dir = __DIR__ . DS . 'I18n' . DS . 'email-templates' . DS;
if (null === MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)) {
$message = new Message();
$message
->setName(self::CONFIRMATION_MESSAGE_NAME)
->setLocale('en_US')
->setTitle('Paybox payment confirmation')
->setSubject('Payment of order {$order_ref}')
->setHtmlMessage(file_get_contents($email_templates_dir . 'en.html'))
->setTextMessage(file_get_contents($email_templates_dir . 'en.txt'))
->setLocale('fr_FR')
->setTitle('Confirmation de paiement par PayBox')
->setSubject('Confirmation du paiement de votre commande {$order_ref}')
->setHtmlMessage(file_get_contents($email_templates_dir . 'fr.html'))
->setTextMessage(file_get_contents($email_templates_dir . 'fr.txt'))
->save();
}
if (null === MessageQuery::create()->findOneByName(self::NOTIFICATION_MESSAGE_NAME)) {
$message = new Message();
$message
->setName(self::NOTIFICATION_MESSAGE_NAME)
->setLocale('en_US')
->setTitle('Paybox payment status notification')
->setSubject('Paybox payment status for order {$order_ref}: {$paybox_payment_status}')
->setHtmlMessage(file_get_contents($email_templates_dir . 'notification-en.html'))
->setTextMessage(file_get_contents($email_templates_dir . 'notification-en.txt'))
->setLocale('fr_FR')
->setTitle('Notification du résultat d\'un paiement par Paybox')
->setSubject('Résultats du paiement Paybox de la commande {$order_ref} : {$paybox_payment_status}')
->setHtmlMessage(file_get_contents($email_templates_dir . 'notification-fr.html'))
->setTextMessage(file_get_contents($email_templates_dir . 'notification-fr.txt'))
->save();
}
/* Deploy the module's image */
$module = $this->getModuleModel();
if (ModuleImageQuery::create()->filterByModule($module)->count() == 0) {
$this->deployImageFolder($module, sprintf('%s/images', __DIR__), $con);
}
}
/**
* @inheritdoc
*/
public function destroy(ConnectionInterface $con = null, $deleteModuleData = false)
{
// Delete config table and messages if required
if ($deleteModuleData) {
MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)->delete($con);
MessageQuery::create()->findOneByName(self::NOTIFICATION_MESSAGE_NAME)->delete($con);
}
}
/**
* Method used by payment gateway.
*
* If this method return a \Thelia\Core\HttpFoundation\Response instance, this response is sent to the
* browser.
*
* In many cases, it's necessary to send a form to the payment gateway.
* On your response you can return this form already completed, ready to be sent
*
* @param Order $order processed order
* @return Response the HTTP response
*/
public function pay(Order $order)
{
return $this->doPay($order, 'SINGLE');
}
/**
* Payment gateway invocation
*
* @param Order $order processed order
* @return Response the HTTP response
*/
protected function doPay(Order $order)
{
if ('TEST' == Paybox::getConfigValue('mode', false)) {
$platformUrl = Paybox::getConfigValue('url_serveur_test', false);
} else {
$platformUrl = Paybox::getConfigValue('url_serveur', false);
}
// Be sure to have a valid platform URL, otherwise give up
if (false === $platformUrl) {
throw new \InvalidArgumentException(
Translator::getInstance()->trans(
"The platform URL is not defined, please check Paybox module configuration.",
[],
Paybox::MODULE_DOMAIN
)
);
}
$hashAlgo = $this->getHashAlgorithm();
$clefPrivee = Paybox::getConfigValue('clef_privee');
// Generate a transaction ID
$transactionId = sprintf("%010d", $order->getId());
$order->setTransactionRef($transactionId)->save();
$paybox_params = [
'PBX_SITE' => Paybox::getConfigValue('numero_site'),
'PBX_RANG' => Paybox::getConfigValue('rang_site'),
'PBX_IDENTIFIANT' => Paybox::getConfigValue('identifiant_interne'),
'PBX_RETOUR' => self::PARAMETRES_RETOUR,
'PBX_HASH' => $hashAlgo,
'PBX_SECRET' => $clefPrivee,
'PBX_ANNULE' => Paybox::getConfigValue('url_retour_abandon'),
'PBX_EFFECTUE' => Paybox::getConfigValue('url_retour_succes'),
'PBX_REFUSE' => Paybox::getConfigValue('url_retour_refus'),
<?php
/*
* This file is part of the Thelia package.
* http://www.thelia.net
*
* (c) OpenStudio <info@thelia.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* Copyright (c) CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
namespace Paybox;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumberUtil;
use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Exception\PropelException;
use Thelia\Core\HttpFoundation\Response;
use Thelia\Core\Translation\Translator;
use Thelia\Log\Tlog;
use Thelia\Model\Message;
use Thelia\Model\MessageQuery;
use Thelia\Model\ModuleImageQuery;
use Thelia\Model\Order;
use Thelia\Module\AbstractPaymentModule;
/**
* Paybox payment module.
*
* @author Franck Allimant <franck@cqfdev.fr>
*/
class Paybox extends AbstractPaymentModule
{
/** The module domain for internationalisation */
const MODULE_DOMAIN = 'paybox';
/** The module domain for internationalisation */
const MODULE_CODE = 'Paybox';
/** The confirmation message identifier */
const CONFIRMATION_MESSAGE_NAME = 'paybox_payment_confirmation';
// Liste des variables retournées par paybox
const PARAMETRES_RETOUR = 'montant:M;ref:R;auto:A;trans:T;erreur:E;sign:K';
/** The notification of payment confirmation */
const NOTIFICATION_MESSAGE_NAME = 'paybox_payment_status_notification';
public function postActivation(ConnectionInterface $con = null): void
{
// Create payment confirmation message from templates, if not already defined
$email_templates_dir = __DIR__.DS.'I18n'.DS.'email-templates'.DS;
if (null === MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)) {
$message = new Message();
$message
->setName(self::CONFIRMATION_MESSAGE_NAME)
->setLocale('en_US')
->setTitle('Paybox payment confirmation')
->setSubject('Payment of order {$order_ref}')
->setHtmlMessage(file_get_contents($email_templates_dir.'en.html'))
->setTextMessage(file_get_contents($email_templates_dir.'en.txt'))
->setLocale('fr_FR')
->setTitle('Confirmation de paiement par PayBox')
->setSubject('Confirmation du paiement de votre commande {$order_ref}')
->setHtmlMessage(file_get_contents($email_templates_dir.'fr.html'))
->setTextMessage(file_get_contents($email_templates_dir.'fr.txt'))
->save();
}
if (null === MessageQuery::create()->findOneByName(self::NOTIFICATION_MESSAGE_NAME)) {
$message = new Message();
$message
->setName(self::NOTIFICATION_MESSAGE_NAME)
->setLocale('en_US')
->setTitle('Paybox payment status notification')
->setSubject('Paybox payment status for order {$order_ref}: {$paybox_payment_status}')
->setHtmlMessage(file_get_contents($email_templates_dir.'notification-en.html'))
->setTextMessage(file_get_contents($email_templates_dir.'notification-en.txt'))
->setLocale('fr_FR')
->setTitle('Notification du résultat d\'un paiement par Paybox')
->setSubject('Résultats du paiement Paybox de la commande {$order_ref} : {$paybox_payment_status}')
->setHtmlMessage(file_get_contents($email_templates_dir.'notification-fr.html'))
->setTextMessage(file_get_contents($email_templates_dir.'notification-fr.txt'))
->save();
}
/* Deploy the module's image */
$module = $this->getModuleModel();
if (ModuleImageQuery::create()->filterByModule($module)->count() == 0) {
$this->deployImageFolder($module, sprintf('%s'.DS.'images', __DIR__), $con);
}
}
public function destroy(ConnectionInterface $con = null, $deleteModuleData = false): void
{
// Delete config table and messages if required
if ($deleteModuleData) {
MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)->delete($con);
MessageQuery::create()->findOneByName(self::NOTIFICATION_MESSAGE_NAME)->delete($con);
}
}
/**
* Method used by payment gateway.
*
* If this method return a \Thelia\Core\HttpFoundation\Response instance, this response is sent to the
* browser.
*
* In many cases, it's necessary to send a form to the payment gateway.
* On your response you can return this form already completed, ready to be sent
*
* @param Order $order processed order
*
* @return Response the HTTP response
*/
public function pay(Order $order): Response
{
return $this->doPay($order);
}
/**
* Payment gateway invocation.
*
* @param Order $order processed order
*
* @return Response the HTTP response
*/
protected function doPay(Order $order): Response
{
if ('TEST' === self::getConfigValue('mode', false)) {
$platformUrl = self::getConfigValue('url_serveur_test', false);
} else {
$platformUrl = self::getConfigValue('url_serveur', false);
}
// Be sure to have a valid platform URL, otherwise give up
if (false === $platformUrl) {
throw new \InvalidArgumentException(
Translator::getInstance()->trans(
'The platform URL is not defined, please check Paybox module configuration.',
[],
self::MODULE_DOMAIN
)
);
}
$hashAlgo = $this->getHashAlgorithm();
$clefPrivee = self::getConfigValue('clef_privee');
$paybox_params = $this->doPayPayboxParameters($order)
+ [
'PBX_HASH' => $hashAlgo,
'PBX_SECRET' => $clefPrivee,
];
// Generate signature
$param = '';
foreach ($paybox_params as $key => $value) {
$param .= '&'.$key.'='.$value;
}
$param = ltrim($param, '&');
$binkey = pack('H*', $clefPrivee);
$paybox_params['PBX_HMAC'] = strtoupper(hash_hmac($hashAlgo, $param, $binkey));
return $this->generateGatewayFormResponse($order, $platformUrl, $paybox_params);
}
protected function doPayPayboxParameters(Order $order): array
{
// Generate a transaction ID
$transactionId = sprintf('%010d', $order->getId());
$order->setTransactionRef($transactionId)->save();
$paybox_params = [
'PBX_SITE' => self::getConfigValue('numero_site'),
'PBX_RANG' => self::getConfigValue('rang_site'),
'PBX_IDENTIFIANT' => self::getConfigValue('identifiant_interne'),
'PBX_RETOUR' => self::PARAMETRES_RETOUR,
'PBX_ANNULE' => self::getConfigValue('url_retour_abandon'),
'PBX_EFFECTUE' => self::getConfigValue('url_retour_succes'),
'PBX_REFUSE' => self::getConfigValue('url_retour_refus'),
'PBX_REPONDRE_A' => self::getConfigValue('url_ipn'),
'PBX_TOTAL' => round(100 * $order->getTotalAmount()),
'PBX_DEVISE' => $this->getCurrencyIso4217NumericCode($order->getCurrency()->getCode()),
'PBX_CMD' => $transactionId,
'PBX_PORTEUR' => $order->getCustomer()->getEmail(),
'PBX_TIME' => date('c'),
'PBX_RUF1' => 'POST',
'PBX_SHOPPINGCART' => $this->getShoppingCart($order),
'PBX_BILLING' => $this->getBilling($order),
];
return $paybox_params;
}
/**
* @throws PropelException
*
* @return array|bool|string|string[]
*/
protected function getBilling(Order $order)
{
$address = $order->getOrderAddressRelatedByInvoiceOrderAddressId();
// Decode phone number
$phoneNumber = empty($address->getCellphone()) ? $address->getPhone() : $address->getCellphone();
$phoneUtil = PhoneNumberUtil::getInstance();
// Default values
$phoneCountryCode = '00';
$phoneNationalNumber = '00000000';
try {
$phoneNumberProto = $phoneUtil->parse($phoneNumber, $address->getCountry()->getIsoalpha2());
$phoneNationalNumber = $phoneNumberProto->getNationalNumber();
$phoneCountryCode = $phoneNumberProto->getCountryCode();
} catch (NumberParseException $e) {
Tlog::getInstance()->error('Failed to parse phone number "'.$phoneNumber.'", error is : '.$e->getMessage());
}
$billingXml = new \SimpleXMLElement('<Billing/>');
$addressXml = $billingXml->addChild('Address');
$addressXml->addChild('FirstName', $address->getFirstname());
$addressXml->addChild('LastName', $address->getLastname());
$addressXml->addChild('Address1', $address->getAddress1());
$addressXml->addChild('ZipCode', $address->getZipcode());
$addressXml->addChild('City', $address->getCity());
$addressXml->addChild('CountryCode', $address->getCountry()->getIsocode());
$addressXml->addChild('CountryCodeMobilePhone', '+'.$phoneCountryCode);
$addressXml->addChild('MobilePhone', $phoneNationalNumber);
return str_replace(["\n", "\r"], '', $billingXml->asXML());
}
/**
* @return array|bool|string|string[]
*/
protected function getShoppingCart(Order $order)
{
$quantity = 0;
$shoppingCartXml = new \SimpleXMLElement('<shoppingcart/>');
foreach ($order->getOrderProducts() as $product) {
$quantity += $product->getQuantity();
}
$total = $shoppingCartXml->addChild('total');
$total->addChild('totalQuantity', $quantity);
return str_replace(["\n", "\r"], '', $shoppingCartXml->asXML());
}
/**
* @return bool true to allow usage of this payment module, false otherwise
*/
public function isValidPayment(): bool
{
$valid = false;
$mode = self::getConfigValue('mode', false);
// If we're in test mode, do not display Paybox on the front office, except for allowed IP addresses.
if ('TEST' === $mode) {
$raw_ips = explode("\n", self::getConfigValue('allowed_ip_list', ''));
$allowed_client_ips = [];
foreach ($raw_ips as $ip) {
$allowed_client_ips[] = trim($ip);
}
$client_ip = $this->getRequest()->getClientIp();
$valid = \in_array($client_ip, $allowed_client_ips);
} elseif ('PRODUCTION' === $mode) {
$valid = true;
}
if ($valid) {
// Check if total order amount is in the module's limits
$valid = $this->checkMinMaxAmount();
}
return $valid;
}
/**
* Check if total order amount is in the module's limits.
*
* @return bool true if the current order total is within the min and max limits
*/
protected function checkMinMaxAmount(): bool
{
// Check if total order amount is in the module's limits
$order_total = $this->getCurrentOrderTotalAmount();
$min_amount = self::getConfigValue('minimum_amount', 0);
$max_amount = self::getConfigValue('maximum_amount', 0);
return $order_total > 0
&& ($min_amount <= 0 || $order_total >= $min_amount)
&& ($max_amount <= 0 || $order_total <= $max_amount);
}
/**
* Get the numeric ISO 4217 code of a currency.
*
* @param string $textCurrencyCode currency textual code, like EUR or USD
*
* @return string the algorithm
*
* @throw \RuntimeException if no algorithm was found.
*/
protected function getCurrencyIso4217NumericCode($textCurrencyCode)
{
$currencies = null;
$localIso417data = __DIR__.DS.'Config'.DS.'iso4217.xml';
$currencyXmlDataUrl = 'http://www.currency-iso.org/dam/downloads/lists/list_one.xml';
$xmlData = @file_get_contents($currencyXmlDataUrl);
try {
$currencies = new \SimpleXMLElement($xmlData);
// Update the local currencies copy.
@file_put_contents($localIso417data, $xmlData);
} catch (\Exception $ex) {
Tlog::getInstance()->warning("Failed to get currency XML data from $currencyXmlDataUrl: ".$ex->getMessage());
try {
$currencies = new \SimpleXMLElement(@file_get_contents($localIso417data));
} catch (\Exception $ex) {
Tlog::getInstance()->warning("Failed to get currency XML data from local copy $localIso417data: ".$ex->getMessage());
}
}
if (null !== $currencies) {
foreach ($currencies->CcyTbl->CcyNtry as $country) {
if ($country->Ccy == $textCurrencyCode) {
return (string) $country->CcyNbr;
}
}
}
// Last chance
switch ($textCurrencyCode) {
case 'USD':
return 840;
case 'GBP':
return 826;
break;
case 'EUR':
return 978;
break;
}
throw new \RuntimeException(
Translator::getInstance()->trans(
'Failed to get ISO 4217 data for currency %curr, payment is not possible.',
['%curr' => $textCurrencyCode]
)
);
}
/**
* Find a suitable hashing algorithm.
*
* @return string the algorithm
*
* @throw \RuntimeException if no algorithm was found.
*/
protected function getHashAlgorithm(): string
{
// Possible hashes
$hashes = [
'sha512',
'sha256',
'sha384',
'ripemd160',
'sha224',
'mdc2',
];
$hashEnabled = hash_algos();
foreach ($hashes as $hash) {
if (\in_array($hash, $hashEnabled)) {
return strtoupper($hash);
}
}
throw new \RuntimeException(
Translator::getInstance()->trans(
'Failed to find a suitable hash algorithm. Please check your PHP configuration.'
)
);
}
}

View File

@@ -3,6 +3,8 @@
Ce module vous permet de proposer à vos clients le système de paiement Paybox.
> Compatible 3Dsv2
### Installation
> Ce module requiert Thelia 2.1 beta1 au minimum
@@ -29,6 +31,8 @@ This module offers to your customers the Paybox payment system.
> This module requires Thelia 2.1 beta1 or newer
> Compatible 3Dsv2
To install the Paybox module, uncompress the archive in the `<thelia root>/local/modules` directory. Be sure that the name of the module's directory is `Paybox` (and not `Paybox-master`, for exemple).
### Usage

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="LICENSE.txt" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="Paybox.php" server="51.254.220.106//web/" local="131390920547656250" remote="131390920800000000" />
<file name="README.md" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="composer.json" server="51.254.220.106//web/" local="131353051200000000" remote="131390168400000000" />
</dwsync>

View File

@@ -4,9 +4,18 @@
"license": "LGPL-3.0+",
"type": "thelia-module",
"require": {
"thelia/installer": "~1.0"
"thelia/installer": "~1.0",
"giggsey/libphonenumber-for-php": "^8.13"
},
"suggest": {
"thelia/paybox3x-module": "This module offers to your customers the Paybox 3x payment system"
},
"extra": {
"installer-name": "Paybox"
},
"config": {
"allow-plugins": {
"thelia/installer": true
}
}
}
}

280
local/modules/Paybox/composer.lock generated Normal file
View File

@@ -0,0 +1,280 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "817096e4d966c233d7648d2c037f288d",
"packages": [
{
"name": "giggsey/libphonenumber-for-php",
"version": "8.13.45",
"source": {
"type": "git",
"url": "https://github.com/giggsey/libphonenumber-for-php.git",
"reference": "142ccdd603e4eeef7de9a7ddbd9ae18c2651dbd6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/142ccdd603e4eeef7de9a7ddbd9ae18c2651dbd6",
"reference": "142ccdd603e4eeef7de9a7ddbd9ae18c2651dbd6",
"shasum": ""
},
"require": {
"giggsey/locale": "^1.7|^2.0",
"php": ">=5.3.2",
"symfony/polyfill-mbstring": "^1.17"
},
"replace": {
"giggsey/libphonenumber-for-php-lite": "self.version"
},
"require-dev": {
"pear/pear-core-minimal": "^1.9",
"pear/pear_exception": "^1.0",
"pear/versioncontrol_git": "^0.5",
"phing/phing": "^2.7",
"php-coveralls/php-coveralls": "^1.0|^2.0",
"symfony/console": "^2.8|^3.0|^v4.4|^v5.2",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "8.x-dev"
}
},
"autoload": {
"psr-4": {
"libphonenumber\\": "src/"
},
"exclude-from-classmap": [
"/src/data/",
"/src/carrier/data/",
"/src/geocoding/data/",
"/src/timezone/data/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Joshua Gigg",
"email": "giggsey@gmail.com",
"homepage": "https://giggsey.com/"
}
],
"description": "PHP Port of Google's libphonenumber",
"homepage": "https://github.com/giggsey/libphonenumber-for-php",
"keywords": [
"geocoding",
"geolocation",
"libphonenumber",
"mobile",
"phonenumber",
"validation"
],
"support": {
"issues": "https://github.com/giggsey/libphonenumber-for-php/issues",
"source": "https://github.com/giggsey/libphonenumber-for-php"
},
"time": "2024-09-06T11:22:54+00:00"
},
{
"name": "giggsey/locale",
"version": "2.6",
"source": {
"type": "git",
"url": "https://github.com/giggsey/Locale.git",
"reference": "37874fa473131247c348059fb7b8985efc18b5ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/giggsey/Locale/zipball/37874fa473131247c348059fb7b8985efc18b5ea",
"reference": "37874fa473131247c348059fb7b8985efc18b5ea",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"require-dev": {
"ext-json": "*",
"pear/pear-core-minimal": "^1.9",
"pear/pear_exception": "^1.0",
"pear/versioncontrol_git": "^0.5",
"phing/phing": "^2.7",
"php-coveralls/php-coveralls": "^2.0",
"phpunit/phpunit": "^8.5|^9.5",
"symfony/console": "^5.0|^6.0",
"symfony/filesystem": "^5.0|^6.0",
"symfony/finder": "^5.0|^6.0",
"symfony/process": "^5.0|^6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Giggsey\\Locale\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joshua Gigg",
"email": "giggsey@gmail.com",
"homepage": "https://giggsey.com/"
}
],
"description": "Locale functions required by libphonenumber-for-php",
"support": {
"issues": "https://github.com/giggsey/Locale/issues",
"source": "https://github.com/giggsey/Locale/tree/2.6"
},
"time": "2024-04-18T19:31:19+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "thelia/installer",
"version": "1.5",
"source": {
"type": "git",
"url": "https://github.com/thelia/installer.git",
"reference": "30b7a084e64bd3a4ffb290fa6d9bf096b64b2b56"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thelia/installer/zipball/30b7a084e64bd3a4ffb290fa6d9bf096b64b2b56",
"reference": "30b7a084e64bd3a4ffb290fa6d9bf096b64b2b56",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0||^2.0"
},
"require-dev": {
"composer/composer": "1.0.*@dev||2.0.*@dev"
},
"type": "composer-plugin",
"extra": {
"class": "Thelia\\Composer\\TheliaInstallerPlugin"
},
"autoload": {
"psr-0": {
"Thelia\\Composer": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "Manuel Raynaud",
"email": "raynaud.manu@gmail.com",
"homepage": "https://github.com/lunika"
}
],
"description": "custom installer for Thelia.",
"keywords": [
"Thelia",
"Thelia-module",
"Thelia-template"
],
"support": {
"issues": "https://github.com/thelia/installer/issues",
"source": "https://github.com/thelia/installer/tree/1.5"
},
"time": "2024-08-12T13:48:42+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="ManuelIntegrationPayboxSystem_V6.2_EN.pdf" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
<file name="PayboxTestParameters_V6.2_EN.pdf" server="51.254.220.106//web/" local="131353051200000000" remote="131390169000000000" />
</dwsync>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dwsync>
<file name="paybox-logo.png" server="51.254.220.106//web/" local="131390905800000000" remote="131390905800000000" />
</dwsync>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB