Il manquait quelques fichiers dans Git
This commit is contained in:
146
local/modules/Axepta/Axepta.php
Executable file
146
local/modules/Axepta/Axepta.php
Executable file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Axepta;
|
||||
|
||||
use Axepta\Util\Axepta as AxeptaPayment;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\Order;
|
||||
use Thelia\Module\AbstractPaymentModule;
|
||||
use Thelia\Tools\MoneyFormat;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class Axepta extends AbstractPaymentModule
|
||||
{
|
||||
/** @var string */
|
||||
public const DOMAIN_NAME = 'axepta';
|
||||
|
||||
public const MERCHANT_ID = 'merchant_id';
|
||||
public const HMAC = 'hmac';
|
||||
public const CRYPT_KEY = 'crypt_key';
|
||||
public const MODE = 'run_mode';
|
||||
public const ALLOWED_IP_LIST = 'allowed_ip_list';
|
||||
public const MINIMUM_AMOUNT = 'minimum_amount';
|
||||
public const MAXIMUM_AMOUNT = 'maximum_amount';
|
||||
|
||||
public const SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID = 'send_confirmation_message_only_if_paid';
|
||||
|
||||
public function pay(Order $order)
|
||||
{
|
||||
$hmac = self::getConfigValue(self::HMAC, null);
|
||||
$merchantId = self::getConfigValue(self::MERCHANT_ID, null);
|
||||
$cryptKey = self::getConfigValue(self::CRYPT_KEY, null);
|
||||
$mode = self::getConfigValue(self::MODE, null);
|
||||
|
||||
$urlAnnulation = $this->getPaymentFailurePageUrl($order->getId(), Translator::getInstance()->trans('Vous avez annulé le paiement', [], Axepta::DOMAIN_NAME));
|
||||
$urlNotification = URL::getInstance()->absoluteUrl('/axepta/notification');
|
||||
|
||||
$paymentRequest = new AxeptaPayment($hmac);
|
||||
$paymentRequest->setCryptKey($cryptKey);
|
||||
|
||||
$transId = time().$order->getId();
|
||||
|
||||
$paymentRequest->setUrl(AxeptaPayment::PAYSSL);
|
||||
$paymentRequest->setMerchantID($merchantId);
|
||||
$paymentRequest->setTransID($transId);
|
||||
$paymentRequest->setAmount((int) ($order->getTotalAmount()*100));
|
||||
$paymentRequest->setCurrency($order->getCurrency()->getCode());
|
||||
$paymentRequest->setRefNr($order->getRef());
|
||||
$paymentRequest->setURLSuccess($urlNotification);
|
||||
$paymentRequest->setURLFailure($urlNotification);
|
||||
$paymentRequest->setURLNotify($urlNotification);
|
||||
$paymentRequest->setURLBack($urlAnnulation);
|
||||
$paymentRequest->setReponse('encrypt');
|
||||
$paymentRequest->setLanguage($this->getRequest()->getSession()->getLang()->getLocale());
|
||||
|
||||
if ($mode === 'TEST') {
|
||||
// See https://docs.axepta.bnpparibas/display/DOCBNP/Test+environment
|
||||
// In the encrypted data request, use the default parameter OrderDesc with the value "Test:0000". This will give you a correspondingly successful authorization after successful authentication.
|
||||
$paymentRequest->setOrderDesc('Test:0000');
|
||||
} else {
|
||||
$paymentRequest->setOrderDesc($order->getCustomer()->getFirstname() . ' ' . $order->getCustomer()->getLastname());
|
||||
}
|
||||
|
||||
$paymentRequest->validate();
|
||||
|
||||
$mac = $paymentRequest->getShaSign();
|
||||
$data = $paymentRequest->getBfishCrypt();
|
||||
$len = $paymentRequest->getLen();
|
||||
|
||||
$transmit = [
|
||||
'MerchantID' => $paymentRequest->getMerchantID(),
|
||||
'Len' => $len,
|
||||
'Data' => $data,
|
||||
'URLBack' => $urlAnnulation,
|
||||
'CustomField1' => sprintf(
|
||||
"%s, %s",
|
||||
MoneyFormat::getInstance($this->getRequest())->format($order->getTotalAmount(), 2),
|
||||
$order->getCurrency()->getCode()
|
||||
),
|
||||
'CustomField2' => $order->getRef()
|
||||
];
|
||||
|
||||
TLog::getInstance()->error("Données Axcepta : " . print_r($paymentRequest->parameters, 1));
|
||||
TLog::getInstance()->error("URL Axcepta : " . $paymentRequest->getUrl());
|
||||
|
||||
$order
|
||||
->setTransactionRef($transId)
|
||||
->save();
|
||||
|
||||
return $this->generateGatewayFormResponse($order, $paymentRequest->getUrl(), $transmit);
|
||||
}
|
||||
|
||||
public function isValidPayment()
|
||||
{
|
||||
$hmac = self::getConfigValue(self::HMAC, null);
|
||||
$merchantId = self::getConfigValue(self::MERCHANT_ID, null);
|
||||
$cryptKey = self::getConfigValue(self::CRYPT_KEY, null);
|
||||
$mode = self::getConfigValue(self::MODE, null);
|
||||
$valid = true;
|
||||
|
||||
if (($hmac === null || $merchantId === null || $cryptKey === null) && $mode !== 'TEST') {
|
||||
Tlog::getInstance()->errro("Axepta module is not properly configured, some configuration data are missing.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($mode === 'TEST') {
|
||||
$raw_ips = explode("\n", self::getConfigValue(self::ALLOWED_IP_LIST, ''));
|
||||
$allowed_client_ips = array();
|
||||
|
||||
foreach ($raw_ips as $ip) {
|
||||
$allowed_client_ips[] = trim($ip);
|
||||
}
|
||||
|
||||
$client_ip = $this->getRequest()->getClientIp();
|
||||
|
||||
$valid = in_array($client_ip, $allowed_client_ips) || in_array('*', $allowed_client_ips);
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
// Check if total order amount is in the module's limits
|
||||
$valid = $this->checkMinMaxAmount(self::MINIMUM_AMOUNT, self::MAXIMUM_AMOUNT);
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
protected function checkMinMaxAmount($min, $max)
|
||||
{
|
||||
$order_total = $this->getCurrentOrderTotalAmount();
|
||||
|
||||
$min_amount = self::getConfigValue($min, 0);
|
||||
$max_amount = self::getConfigValue($max, 0);
|
||||
|
||||
return $order_total > 0 && ($min_amount <= 0 || $order_total >= $min_amount) && ($max_amount <= 0 || $order_total <= $max_amount);
|
||||
}
|
||||
}
|
||||
25
local/modules/Axepta/Config/config.xml
Executable file
25
local/modules/Axepta/Config/config.xml
Executable file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<forms>
|
||||
<form name="axepta_configuration" class="Axepta\Form\ConfigurationForm" />
|
||||
</forms>
|
||||
|
||||
<services>
|
||||
<service id="axepta.send.confirmation_mail" class="Axepta\EventListeners\SendConfirmationEmail">
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
<hooks>
|
||||
<hook id="axepta.configuration.hook" class="Axepta\Hook\HookManager">
|
||||
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfigure" />
|
||||
</hook>
|
||||
<hook id="axepta.orderpaymentgateway.hook" class="Axepta\Hook\HookManager">
|
||||
<tag name="hook.event_listener" event="order-payment-gateway.javascript" type="front" method="onOrderPaymentGatewayJavascript" />
|
||||
</hook>
|
||||
</hooks>
|
||||
</config>
|
||||
28
local/modules/Axepta/Config/module.xml
Executable file
28
local/modules/Axepta/Config/module.xml
Executable file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module xmlns="http://thelia.net/schema/dic/module"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
|
||||
<fullnamespace>Axepta\Axepta</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Payement with Axepta</title>
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Paiement avec Axepta</title>
|
||||
</descriptive>
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version>1.0.1</version>
|
||||
<authors>
|
||||
<author>
|
||||
<name>Nicolas Barbey</name>
|
||||
<email>nbarbey@openstudio.fr</email>
|
||||
</author>
|
||||
</authors>
|
||||
<type>classic</type>
|
||||
<thelia>2.3.0</thelia>
|
||||
<stability>other</stability>
|
||||
<mandatory>0</mandatory>
|
||||
<hidden>0</hidden>
|
||||
</module>
|
||||
14
local/modules/Axepta/Config/routing.xml
Executable file
14
local/modules/Axepta/Config/routing.xml
Executable file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<routes xmlns="http://symfony.com/schema/routing"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
|
||||
|
||||
<route id="axepta.configure" path="/admin/module/axepta/configure" methods="post">
|
||||
<default key="_controller">Axepta\Controller\ConfigurationController::configure</default>
|
||||
</route>
|
||||
|
||||
<route id="axepta.notification_url" path="/axepta/notification">
|
||||
<default key="_controller">Axepta\Controller\NotificationController::notificationAction</default>
|
||||
</route>
|
||||
</routes>
|
||||
80
local/modules/Axepta/Controller/ConfigurationController.php
Executable file
80
local/modules/Axepta/Controller/ConfigurationController.php
Executable file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Axepta\Controller;
|
||||
|
||||
use Axepta\Axepta;
|
||||
use Thelia\Controller\Admin\BaseAdminController;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class ConfigurationController extends BaseAdminController
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'Axepta', AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Create the Form from the request
|
||||
$configurationForm = $this->createForm('axepta_configuration');
|
||||
|
||||
try {
|
||||
// Check the form against constraints violations
|
||||
$form = $this->validateForm($configurationForm, "POST");
|
||||
|
||||
// Get the form field values
|
||||
$data = $form->getData();
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(';', $value);
|
||||
}
|
||||
|
||||
Axepta::setConfigValue($name, $value);
|
||||
}
|
||||
|
||||
// Log configuration modification
|
||||
$this->adminLogAppend(
|
||||
"axepta.configuration.message",
|
||||
AccessManager::UPDATE,
|
||||
"Axepta configuration updated"
|
||||
);
|
||||
|
||||
// Redirect to the success URL,
|
||||
if ($this->getRequest()->get('save_mode') === 'stay') {
|
||||
// If we have to stay on the same page, redisplay the configuration page/
|
||||
$route = '/admin/module/Axepta';
|
||||
} else {
|
||||
// If we have to close the page, go back to the module back-office page.
|
||||
$route = '/admin/modules';
|
||||
}
|
||||
|
||||
return $this->generateRedirect(URL::getInstance()->absoluteUrl($route));
|
||||
|
||||
// An exit is performed after redirect.+
|
||||
} catch (FormValidationException $ex) {
|
||||
// Form cannot be validated. Create the error message using
|
||||
// the BaseAdminController helper method.
|
||||
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
|
||||
} catch (\Exception $ex) {
|
||||
// Any other error
|
||||
$error_msg = $ex->getMessage();
|
||||
}
|
||||
|
||||
// At this point, the form has errors, and should be redisplayed. We do not redirect,
|
||||
// just redisplay the same template.
|
||||
// Set up the Form error context, to make error information available in the template.
|
||||
$this->setupFormErrorContext(
|
||||
$this->getTranslator()->trans("Axepta configuration", [], Axepta::DOMAIN_NAME),
|
||||
$error_msg,
|
||||
$configurationForm,
|
||||
$ex
|
||||
);
|
||||
|
||||
// Do not redirect at this point, or the error context will be lost.
|
||||
// Just redisplay the current template.
|
||||
return $this->render('module-configure', array('module_code' => 'Payline'));
|
||||
}
|
||||
}
|
||||
68
local/modules/Axepta/Controller/NotificationController.php
Executable file
68
local/modules/Axepta/Controller/NotificationController.php
Executable file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Axepta\Controller;
|
||||
|
||||
use Axepta\Axepta;
|
||||
use Axepta\Util\Axepta as AxeptaPayment;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Exception\TheliaProcessException;
|
||||
use Thelia\Model\Base\OrderQuery;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
use Thelia\Module\BasePaymentModuleController;
|
||||
|
||||
class NotificationController extends BasePaymentModuleController
|
||||
{
|
||||
protected function getModuleCode()
|
||||
{
|
||||
return 'Axepta';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function notificationAction()
|
||||
{
|
||||
$this->getLog()->addInfo("Processing Axcepta notification");
|
||||
|
||||
$paymentResponse = new AxeptaPayment(Axepta::getConfigValue(Axepta::HMAC));
|
||||
$paymentResponse->setCryptKey(Axepta::getConfigValue(Axepta::CRYPT_KEY));
|
||||
$paymentResponse->setResponse($this->getRequest()->query->all());
|
||||
|
||||
$this->getLog()->addError("Notification parameters: ".print_r($paymentResponse->parameters, 1));
|
||||
|
||||
$transId = $paymentResponse->getTransID();
|
||||
|
||||
if (null === $order = OrderQuery::create()->filterByTransactionRef($transId)->findOne()) {
|
||||
$this->getLog()->addInfo("Failed to fin order for transaction ID $transId. Aborting.");
|
||||
|
||||
throw new TheliaProcessException(
|
||||
Translator::getInstance()->trans("Failed to find order for transaction ID %id", ['id' => $transId ], Axepta::DOMAIN_NAME)
|
||||
);
|
||||
}
|
||||
|
||||
$this->getLog()->addInfo("Processing payment of order " . $order->getRef());
|
||||
|
||||
$event = new OrderEvent($order);
|
||||
|
||||
if ($paymentResponse->isValid() && $paymentResponse->isSuccessful()) {
|
||||
$this->getLog()->addInfo("Payment of order ".$order->getRef()." is successful.");
|
||||
if (!$order->isPaid()) {
|
||||
$this->getLog()->addInfo("Setting order status to 'paid'.");
|
||||
$event->setStatus(OrderStatusQuery::getPaidStatus()->getId());
|
||||
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
|
||||
}
|
||||
|
||||
$this->redirectToSuccessPage($order->getId());
|
||||
}
|
||||
|
||||
$this->getLog()->addInfo("Payment failed, cancelling order " . $order->getRef());
|
||||
|
||||
$event->setStatus(OrderStatusQuery::getCancelledStatus()->getId());
|
||||
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
|
||||
|
||||
$this->getLog()->addInfo("Failure cause:".$paymentResponse->getDescription() . ' ('.$paymentResponse->getCode());
|
||||
$this->redirectToFailurePage($order->getId(), $paymentResponse->getDescription() . ' ('.$paymentResponse->getCode().')');
|
||||
}
|
||||
}
|
||||
82
local/modules/Axepta/EventListeners/SendConfirmationEmail.php
Executable file
82
local/modules/Axepta/EventListeners/SendConfirmationEmail.php
Executable file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* */
|
||||
/* Thelia */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : info@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify */
|
||||
/* it under the terms of the GNU General Public License as published by */
|
||||
/* the Free Software Foundation; either version 3 of the License */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, */
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* GNU General Public License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Axepta\EventListeners;
|
||||
|
||||
use Axepta\Axepta;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Action\BaseAction;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
* Axepta payment module
|
||||
*
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class SendConfirmationEmail extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if the message cannot be loaded.
|
||||
*/
|
||||
public function sendConfirmationEmail(OrderEvent $event)
|
||||
{
|
||||
if (Axepta::getConfigValue(Axepta::SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID, true)) {
|
||||
// We send the order confirmation email only if the order is paid
|
||||
$order = $event->getOrder();
|
||||
|
||||
if (!$order->isPaid() && $order->getPaymentModuleId() === (int) Axepta::getModuleId()) {
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if order payment module is Axepta and if order new status is paid, send a confirmation email to the customer.
|
||||
*
|
||||
* @param OrderEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function updateStatus(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
if ($order->isPaid() && $order->getPaymentModuleId() === Axepta::getModuleId()) {
|
||||
$dispatcher->dispatch(TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL, $event);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => array("updateStatus", 128),
|
||||
TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => array("sendConfirmationEmail", 129)
|
||||
);
|
||||
}
|
||||
}
|
||||
150
local/modules/Axepta/Form/ConfigurationForm.php
Executable file
150
local/modules/Axepta/Form/ConfigurationForm.php
Executable file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Axepta\Form;
|
||||
|
||||
use Axepta\Axepta;
|
||||
use Payline\Payline;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Form\BaseForm;
|
||||
|
||||
class ConfigurationForm extends BaseForm
|
||||
{
|
||||
protected function buildForm()
|
||||
{
|
||||
$this->formBuilder
|
||||
->add(
|
||||
Axepta::MODE,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'constraints' => [new NotBlank()],
|
||||
'required' => true,
|
||||
'choices' => [
|
||||
'TEST' => 'Test',
|
||||
'PRODUCTION' => 'Production',
|
||||
],
|
||||
'label' => $this->trans('Mode de fonctionnement', []),
|
||||
'data' => Axepta::getConfigValue(Axepta::MODE),
|
||||
]
|
||||
)
|
||||
->add(
|
||||
Axepta::MERCHANT_ID,
|
||||
TextType::class,
|
||||
[
|
||||
'constraints' => [new NotBlank()],
|
||||
'required' => true,
|
||||
'label' => $this->trans('Merchant ID'),
|
||||
'data' => Axepta::getConfigValue(Axepta::MERCHANT_ID, ''),
|
||||
]
|
||||
)
|
||||
->add(
|
||||
Axepta::HMAC,
|
||||
TextType::class,
|
||||
[
|
||||
'constraints' => [new NotBlank()],
|
||||
'required' => true,
|
||||
'label' => $this->trans('HMAC key'),
|
||||
'data' => Axepta::getConfigValue(Axepta::HMAC, ''),
|
||||
]
|
||||
)
|
||||
->add(
|
||||
Axepta::CRYPT_KEY,
|
||||
TextType::class,
|
||||
[
|
||||
'constraints' => [new NotBlank()],
|
||||
'required' => true,
|
||||
'label' => $this->trans('Blowfish encryption key'),
|
||||
'data' => Axepta::getConfigValue(Axepta::CRYPT_KEY, ''),
|
||||
]
|
||||
)
|
||||
->add(
|
||||
Axepta::ALLOWED_IP_LIST,
|
||||
TextareaType::class,
|
||||
[
|
||||
'required' => false,
|
||||
'label' => $this->trans('Allowed IPs in test mode'),
|
||||
'data' => Axepta::getConfigValue(Axepta::ALLOWED_IP_LIST),
|
||||
'label_attr' => array(
|
||||
'for' => Axepta::ALLOWED_IP_LIST,
|
||||
'help' => $this->trans(
|
||||
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line',
|
||||
array('%ip' => $this->getRequest()->getClientIp())
|
||||
),
|
||||
'rows' => 3
|
||||
)
|
||||
]
|
||||
)
|
||||
->add(
|
||||
Axepta::MINIMUM_AMOUNT,
|
||||
NumberType::class,
|
||||
array(
|
||||
'constraints' => array(
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual(array('value' => 0))
|
||||
),
|
||||
'required' => true,
|
||||
'label' => $this->trans('Minimum order total'),
|
||||
'data' => Axepta::getConfigValue(Axepta::MINIMUM_AMOUNT, 0),
|
||||
'label_attr' => array(
|
||||
'for' => 'minimum_amount',
|
||||
'help' => $this->trans('Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum')
|
||||
),
|
||||
'attr' => [
|
||||
'step' => 'any'
|
||||
]
|
||||
)
|
||||
)
|
||||
->add(
|
||||
Axepta::MAXIMUM_AMOUNT,
|
||||
NumberType::class,
|
||||
array(
|
||||
'constraints' => array(
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual(array('value' => 0))
|
||||
),
|
||||
'required' => true,
|
||||
'label' => $this->trans('Maximum order total'),
|
||||
'data' => Axepta::getConfigValue(Axepta::MAXIMUM_AMOUNT, 0),
|
||||
'label_attr' => array(
|
||||
'for' => 'maximum_amount',
|
||||
'help' => $this->trans('Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum')
|
||||
),
|
||||
'attr' => [
|
||||
'step' => 'any'
|
||||
]
|
||||
)
|
||||
)
|
||||
->add(
|
||||
Axepta::SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID,
|
||||
'checkbox',
|
||||
[
|
||||
'value' => 1,
|
||||
'required' => false,
|
||||
'label' => $this->trans('Send order confirmation on payment success'),
|
||||
'data' => (boolean)(Axepta::getConfigValue(Axepta::SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID, true)),
|
||||
'label_attr' => [
|
||||
'help' => $this->trans(
|
||||
'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator'
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'axepta_configuration';
|
||||
}
|
||||
|
||||
protected function trans($str, $params = [])
|
||||
{
|
||||
return Translator::getInstance()->trans($str, $params, Axepta::DOMAIN_NAME);
|
||||
}
|
||||
}
|
||||
23
local/modules/Axepta/Hook/HookManager.php
Executable file
23
local/modules/Axepta/Hook/HookManager.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Axepta\Hook;
|
||||
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
|
||||
class HookManager extends BaseHook
|
||||
{
|
||||
public function onModuleConfigure(HookRenderEvent $event)
|
||||
{
|
||||
$event->add(
|
||||
$this->render('module-configuration.html')
|
||||
);
|
||||
}
|
||||
|
||||
public function onOrderPaymentGatewayJavascript(HookRenderEvent $event)
|
||||
{
|
||||
$event->add(
|
||||
$this->render('hook/order-payment-gateway-javascript.html')
|
||||
);
|
||||
}
|
||||
}
|
||||
6
local/modules/Axepta/I18n/backOffice/default/fr_FR.php
Executable file
6
local/modules/Axepta/I18n/backOffice/default/fr_FR.php
Executable file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Access to Axepta Platform' => 'Accès a Axepta',
|
||||
'Payment configuration' => 'Configuration de paiement',
|
||||
);
|
||||
6
local/modules/Axepta/I18n/en_US.php
Executable file
6
local/modules/Axepta/I18n/en_US.php
Executable file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Mode de fonctionnement' => 'Operation Mode',
|
||||
'Vous avez annulé le paiement' => 'You have cancel the payment',
|
||||
);
|
||||
16
local/modules/Axepta/I18n/fr_FR.php
Executable file
16
local/modules/Axepta/I18n/fr_FR.php
Executable file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Allowed IPs in test mode' => 'Adresse IP autorisé en mode de test ',
|
||||
'Blowfish encryption key' => 'Clé de cryptage Blowfish',
|
||||
'Failed to find order reference %ref' => 'La référence de commande %ref n\'a pas été trouvé',
|
||||
'HMAC key' => 'Clé HMAC',
|
||||
'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator' => 'Si cette case est cochée, le mail de confirmation de commande sera envoyé au client seulement si son paiement est validé.',
|
||||
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line' => 'Liste des adresses IP qui pourront choisir ce module de paiement en front-office pendant la phase de test (votre IP est 127.0.0.1). Une adresse par ligne.',
|
||||
'Maximum order total' => 'Montant maximum de commande',
|
||||
'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum' => 'Montant maximum dans la devise par défaut pour proposer ce moyen de paiement. Laisser 0 pour ne pas fixer de maximum',
|
||||
'Merchant ID' => 'Id du commerçant',
|
||||
'Minimum order total' => 'Montant minimum de commande',
|
||||
'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum' => 'Montant minimum dans la devise par défaut pour proposer ce moyen de paiement. Laisser 0 pour ne pas fixer de minimum',
|
||||
'Send order confirmation on payment success' => 'Confirmation de commande si le paiement réussit',
|
||||
);
|
||||
27
local/modules/Axepta/Readme.md
Executable file
27
local/modules/Axepta/Readme.md
Executable file
@@ -0,0 +1,27 @@
|
||||
# Axepta
|
||||
|
||||
This module adds the payment solution Axepta.
|
||||
|
||||
## Installation
|
||||
|
||||
### Manually
|
||||
|
||||
* Copy the module into ```<thelia_root>/local/modules/``` directory and be sure that the name of the module is Axepta.
|
||||
* Activate it in your thelia administration panel
|
||||
|
||||
### Composer
|
||||
|
||||
Add it in your main thelia composer.json file
|
||||
|
||||
```
|
||||
composer require thelia/axepta-module:~1.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
* Contact Axepta to create an account.
|
||||
* Go to the module configuration and add your HMAC key, Blowfish encryption key, and your merchant id.
|
||||
* Set the operation mode to production
|
||||
|
||||
Documentation : https://docs.axepta.bnpparibas
|
||||
|
||||
If you want to test your configuration you can use this credit cards : https://docs.axepta.bnpparibas/display/DOCBNP/Test+Cards
|
||||
488
local/modules/Axepta/Util/Axepta.php
Executable file
488
local/modules/Axepta/Util/Axepta.php
Executable file
@@ -0,0 +1,488 @@
|
||||
<?php
|
||||
|
||||
namespace Axepta\Util;
|
||||
|
||||
class Axepta
|
||||
{
|
||||
const PAYSSL = "https://paymentpage.axepta.bnpparibas/payssl.aspx";
|
||||
const DIRECT = "https://paymentpage.axepta.bnpparibas/direct.aspx";
|
||||
|
||||
const DIRECT3D = "https://paymentpage.axepta.bnpparibas/direct3d.aspx";
|
||||
const CAPTURE = "https://paymentpage.axepta.bnpparibas/capture.aspx";
|
||||
const CREDIT = "https://paymentpage.axepta.bnpparibas/credit.aspx";
|
||||
|
||||
const INSTALMENT = "INSTALMENT";
|
||||
|
||||
|
||||
private $secretKey;
|
||||
|
||||
private $cryptKey;
|
||||
|
||||
private $pspURL = self::PAYSSL;
|
||||
|
||||
public $parameters = array();
|
||||
|
||||
/** Axepta fields **/
|
||||
private $pspFields = array(
|
||||
'Debug',
|
||||
'PayID',
|
||||
'TransID',
|
||||
'MerchantID',
|
||||
'Amount',
|
||||
'Currency',
|
||||
'MAC',
|
||||
|
||||
'RefNr',
|
||||
'Amount3D',
|
||||
'URLSuccess',
|
||||
'URLFailure',
|
||||
'URLNotify',
|
||||
'Response',
|
||||
'UserData',
|
||||
'Capture',
|
||||
'OrderDesc',
|
||||
'ReqID',
|
||||
'Plain',
|
||||
'Custom',
|
||||
'expirationTime',
|
||||
'AccVerify',
|
||||
'RTF',
|
||||
'ChDesc',
|
||||
|
||||
'Len',
|
||||
'Data',
|
||||
|
||||
'Template',
|
||||
'Language',
|
||||
'Background',
|
||||
'URLBack',
|
||||
'CCSelect',
|
||||
|
||||
|
||||
'MID',
|
||||
'mid',
|
||||
'refnr',
|
||||
'XID',
|
||||
'Status',
|
||||
'Description',
|
||||
'Code',
|
||||
'PCNr',
|
||||
'CCNr',
|
||||
'CCCVC',
|
||||
'CCBrand',
|
||||
'CCExpiry',
|
||||
'TermURL',
|
||||
'UserAgent',
|
||||
'HTTPAccept',
|
||||
'AboID',
|
||||
'ACSXID',
|
||||
'MaskedPan',
|
||||
'CAVV',
|
||||
'ECI',
|
||||
'DDD',
|
||||
'Type',
|
||||
'Plain',
|
||||
'Custom',
|
||||
'CustomField1','CustomField2','CustomField3','CustomField4','CustomField5','CustomField6','CustomField7',
|
||||
'CustomField8','CustomField9','CustomField10','CustomField11','CustomField12','CustomField13','CustomField14'
|
||||
|
||||
);
|
||||
/** Axepta request hmac fields **/
|
||||
private $QHMACFields = array(
|
||||
'PayID', 'TransID', 'MerchantID', 'Amount','Currency'
|
||||
);
|
||||
/** Axepta response hmac fields **/
|
||||
private $RHMACFields = array(
|
||||
'PayID', 'TransID', 'MerchantID', 'Status','Code'
|
||||
);
|
||||
|
||||
/** Axepta blowfish crypt fields **/
|
||||
private $BfishFields = array(
|
||||
'PayID','TransID','Amount','Currency','MAC',
|
||||
'RefNr','Amount3D','URLSuccess','URLFailure','URLNotify','Response','UserData','Capture','OrderDesc','ReqID',
|
||||
'Plain','Custom','expirationTime','AccVerify','RTF','ChDesc',
|
||||
'MID','XID','Status','Description','Code','PCNr','CCNr','CCCVC','CCBrand','CCExpiry','TermURL','UserAgent',
|
||||
'HTTPAccept','AboID','ACSXID','MaskedPan','CAVV','ECI','DDD','Type','Plain','Custom'
|
||||
// 'CustomField1','CustomField2','CustomField3','CustomField4','CustomField5','CustomField6','CustomField7',
|
||||
// 'CustomField8','CustomField9','CustomField10','CustomField11','CustomField12','CustomField13','CustomField14'
|
||||
);
|
||||
|
||||
/** Axepta request required fields **/
|
||||
private $requiredFields = array(
|
||||
// 'MerchantID', 'TransID', 'Amount', 'Currency','URLSuccess','URLFailure','URLNotify','OrderDesc'
|
||||
'MerchantID', 'TransID', 'Amount', 'Currency','OrderDesc'
|
||||
);
|
||||
|
||||
public $allowedlanguages = array(
|
||||
'nl', 'fr', 'de', 'it', 'es', 'cy', 'en'
|
||||
);
|
||||
|
||||
|
||||
public function __construct($secret)
|
||||
{
|
||||
$this->secretKey = $secret; // HMAC key
|
||||
}
|
||||
|
||||
public function setCryptKey($secret)
|
||||
{
|
||||
$this->cryptKey = $secret; // blowfish crypt key
|
||||
}
|
||||
|
||||
/** hack to retrieve response field **/
|
||||
public function setReponse($encrypt='encrypt')
|
||||
{
|
||||
$this->parameters['Response'] = $encrypt;
|
||||
}
|
||||
|
||||
/** HMAC compute and store in MAC field**/
|
||||
public function shaCompose(array $parameters)
|
||||
{
|
||||
// compose SHA string
|
||||
$shaString = '';
|
||||
foreach($parameters as $key) {
|
||||
if(array_key_exists($key, $this->parameters) && !empty($this->parameters[$key])) {
|
||||
$value = $this->parameters[$key];
|
||||
$shaString .= $value;
|
||||
}
|
||||
$shaString .= (array_search($key, $parameters) != (count($parameters)-1)) ? '*' : '';
|
||||
}
|
||||
$this->parameters['MAC'] = hash_hmac('sha256', $shaString, $this->secretKey);
|
||||
return $this->parameters['MAC'];
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getShaSign()
|
||||
{
|
||||
$this->validate();
|
||||
return $this->shaCompose($this->QHMACFields);
|
||||
}
|
||||
|
||||
public function BfishCompose(array $parameters)
|
||||
{
|
||||
// compose Blowfish hex string
|
||||
$blowfishString = '';
|
||||
|
||||
foreach($parameters as $key) {
|
||||
if(array_key_exists($key, $this->parameters) && !empty($this->parameters[$key])) {
|
||||
$value = $this->parameters[$key];
|
||||
$blowfishString .= $key.'='.$value.'&';
|
||||
}
|
||||
}
|
||||
$blowfishString = rtrim($blowfishString,'&');
|
||||
$this->parameters['Debug'] = $blowfishString;
|
||||
$this->parameters['Len'] = strlen($blowfishString);
|
||||
$this->parameters[self::DATA_FIELD] = bin2hex($this->encrypt($blowfishString,$this->cryptKey));
|
||||
|
||||
return $this->parameters[self::DATA_FIELD];
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getBfishCrypt()
|
||||
{
|
||||
$this->validate();
|
||||
return $this->BFishCompose($this->BfishFields);
|
||||
}
|
||||
|
||||
private function encrypt($data, $key)
|
||||
{
|
||||
$l = strlen($key);
|
||||
if ($l < 16)
|
||||
$key = str_repeat($key, ceil(16/$l));
|
||||
|
||||
if ($m = strlen($data)%8)
|
||||
$data .= str_repeat("\x00", 8 - $m);
|
||||
if (function_exists('mcrypt_encrypt'))
|
||||
$val = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB);
|
||||
else
|
||||
$val = openssl_encrypt($data, 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
private function decrypt($data, $key)
|
||||
{
|
||||
$l = strlen($key);
|
||||
if ($l < 16)
|
||||
$key = str_repeat($key, ceil(16/$l));
|
||||
|
||||
if (function_exists('mcrypt_encrypt'))
|
||||
$val = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB);
|
||||
else
|
||||
$val = openssl_decrypt($data, 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
|
||||
return rtrim($val, "\0");
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->pspURL;
|
||||
}
|
||||
|
||||
public function setUrl($pspUrl)
|
||||
{
|
||||
$this->validateUri($pspUrl);
|
||||
$this->pspURL = $pspUrl;
|
||||
}
|
||||
|
||||
public function setURLSuccess($url)
|
||||
{
|
||||
$this->validateUri($url);
|
||||
$this->parameters['URLSuccess'] = $url;
|
||||
}
|
||||
|
||||
public function setURLFailure($url)
|
||||
{
|
||||
$this->validateUri($url);
|
||||
$this->parameters['URLFailure'] = $url;
|
||||
}
|
||||
|
||||
public function setURLNotify($url)
|
||||
{
|
||||
$this->validateUri($url);
|
||||
$this->parameters['URLNotify'] = $url;
|
||||
}
|
||||
|
||||
public function setTransID($transactionReference)
|
||||
{
|
||||
if(preg_match('/[^a-zA-Z0-9_-]/', $transactionReference)) {
|
||||
throw new \InvalidArgumentException("TransactionReference cannot contain special characters");
|
||||
}
|
||||
$this->parameters['TransID'] = $transactionReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set amount in cents, eg EUR 12.34 is written as 1234
|
||||
*/
|
||||
public function setAmount($amount)
|
||||
{
|
||||
if(!is_int($amount)) {
|
||||
throw new \InvalidArgumentException("Integer expected. Amount is always in cents");
|
||||
}
|
||||
if($amount <= 0) {
|
||||
throw new \InvalidArgumentException("Amount must be a positive number");
|
||||
}
|
||||
$this->parameters['Amount'] = $amount;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function setCaptureDay($number)
|
||||
{
|
||||
if (strlen($number) > 2) {
|
||||
throw new \InvalidArgumentException("captureDay is too long");
|
||||
}
|
||||
$this->parameters['captureDay'] = $number;
|
||||
}
|
||||
|
||||
// Methodes liees a la lutte contre la fraude
|
||||
|
||||
public function setFraudDataBypass3DS($value)
|
||||
{
|
||||
if(strlen($value) > 128) {
|
||||
throw new \InvalidArgumentException("fraudData.bypass3DS is too long");
|
||||
}
|
||||
$this->parameters['fraudData.bypass3DS'] = $value;
|
||||
}
|
||||
|
||||
// Methodes liees au paiement one-click
|
||||
|
||||
public function setMerchantWalletId($wallet)
|
||||
{
|
||||
if(strlen($wallet) > 21) {
|
||||
throw new \InvalidArgumentException("merchantWalletId is too long");
|
||||
}
|
||||
$this->parameters['merchantWalletId'] = $wallet;
|
||||
}
|
||||
|
||||
public function setPaymentPattern($paymentPattern)
|
||||
{
|
||||
$this->parameters['paymentPattern'] = $paymentPattern;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if(substr($method, 0, 3) == 'set') {
|
||||
// $field = lcfirst(substr($method, 3));
|
||||
$field = substr($method, 3);
|
||||
if(in_array($field, $this->pspFields)) {
|
||||
$this->parameters[$field] = $args[0];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(substr($method, 0, 3) == 'get') {
|
||||
// $field = lcfirst(substr($method, 3));
|
||||
$field = substr($method, 3);
|
||||
if(array_key_exists($field, $this->parameters)) {
|
||||
return $this->parameters[$field];
|
||||
}
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException("Unknown method $method");
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
public function toParameterString()
|
||||
{
|
||||
$parameterString = "";
|
||||
foreach($this->parameters as $key => $value) {
|
||||
$parameterString .= $key . '=' . $value;
|
||||
$parameterString .= (array_search($key, array_keys($this->parameters)) != (count($this->parameters)-1)) ? '|' : '';
|
||||
}
|
||||
|
||||
return $parameterString;
|
||||
}
|
||||
|
||||
|
||||
public static function createFromArray($shaComposer, array $parameters)
|
||||
{
|
||||
$instance = new static($shaComposer);
|
||||
foreach($parameters as $key => $value)
|
||||
{
|
||||
$instance->{"set$key"}($value);
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
foreach($this->requiredFields as $field) {
|
||||
if(empty($this->parameters[$field])) {
|
||||
throw new \RuntimeException($field . " can not be empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function validateUri($uri)
|
||||
{
|
||||
if(!filter_var($uri, FILTER_VALIDATE_URL)) {
|
||||
throw new \InvalidArgumentException("Uri is not valid");
|
||||
}
|
||||
if(strlen($uri) > 200) {
|
||||
throw new \InvalidArgumentException("Uri is too long");
|
||||
}
|
||||
}
|
||||
|
||||
// Traitement des reponses d'Axepta
|
||||
// -----------------------------------
|
||||
|
||||
/** @var string */
|
||||
const SHASIGN_FIELD = "MAC";
|
||||
|
||||
/** @var string */
|
||||
const DATA_FIELD = "Data";
|
||||
|
||||
public function setResponse(array $httpRequest)
|
||||
{
|
||||
// use lowercase internally
|
||||
// $httpRequest = array_change_key_case($httpRequest, CASE_UPPER);
|
||||
|
||||
// set sha sign
|
||||
// $this->shaSign = $this->extractShaSign($httpRequest);
|
||||
|
||||
// filter request for Sips parameters
|
||||
$this->parameters = $this->filterRequestParameters($httpRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $shaSign;
|
||||
|
||||
private $dataString;
|
||||
|
||||
/**
|
||||
* Filter http request parameters
|
||||
* @param array $requestParameters
|
||||
*/
|
||||
private function filterRequestParameters(array $httpRequest)
|
||||
{
|
||||
//filter request for Sips parameters
|
||||
$parameters = $this->parameters;
|
||||
if(!array_key_exists(self::DATA_FIELD, $httpRequest) || $httpRequest[self::DATA_FIELD] == '') {
|
||||
// throw new InvalidArgumentException('Data parameter not present in parameters.');
|
||||
$parameters['Debug'] = implode('&',$httpRequest);
|
||||
foreach($httpRequest as $key=>$value) {
|
||||
$key = ($key=='mid')? 'MerchantID':$key;
|
||||
$parameters[$key]=$value;
|
||||
}
|
||||
} else {
|
||||
$parameters[self::DATA_FIELD] = $httpRequest[self::DATA_FIELD];
|
||||
$this->dataString = $this->decrypt(hex2bin($parameters[self::DATA_FIELD]),$this->cryptKey);
|
||||
$parameters['Debug'] = $this->dataString;
|
||||
$dataParams = explode('&', $this->dataString);
|
||||
foreach($dataParams as $dataParamString) {
|
||||
$dataKeyValue = explode('=',$dataParamString,2);
|
||||
$key = ($dataKeyValue[0]=='mid')?'MerchantID':$dataKeyValue[0];
|
||||
$parameters[$key] = $dataKeyValue[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
public function getSeal()
|
||||
{
|
||||
return $this->shaSign;
|
||||
}
|
||||
|
||||
private function extractShaSign(array $parameters)
|
||||
{
|
||||
if(!array_key_exists(self::SHASIGN_FIELD, $parameters) || $parameters[self::SHASIGN_FIELD] == '') {
|
||||
throw new \InvalidArgumentException('SHASIGN parameter not present in parameters.');
|
||||
}
|
||||
return $parameters[self::SHASIGN_FIELD];
|
||||
}
|
||||
|
||||
public function isValid()
|
||||
{
|
||||
// return $this->shaCompose($this->RHMACFields) == $this->shaSign;
|
||||
return $this->shaCompose($this->RHMACFields) == $this->parameters['MAC'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a response parameter
|
||||
* @param string $param
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getParam($key)
|
||||
{
|
||||
if(method_exists($this, 'get'.$key)) {
|
||||
return $this->{'get'.$key}();
|
||||
}
|
||||
|
||||
// always use uppercase
|
||||
// $key = strtoupper($key);
|
||||
// $parameters = array_change_key_case($this->parameters,CASE_UPPER);
|
||||
$parameters = $this->parameters;
|
||||
if(!array_key_exists($key, $parameters)) {
|
||||
throw new \InvalidArgumentException('Parameter ' . $key . ' does not exist.');
|
||||
}
|
||||
|
||||
return $parameters[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Amount in cents
|
||||
*/
|
||||
public function getAmount()
|
||||
{
|
||||
$value = trim($this->parameters['Amount']);
|
||||
return (int) ($value);
|
||||
}
|
||||
|
||||
public function isSuccessful()
|
||||
{
|
||||
return in_array($this->getParam('Status'), array("OK", "AUTHORIZED"));
|
||||
}
|
||||
|
||||
public function getDataString()
|
||||
{
|
||||
return $this->dataString;
|
||||
}
|
||||
}
|
||||
12
local/modules/Axepta/composer.json
Executable file
12
local/modules/Axepta/composer.json
Executable file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "thelia/axepta-module",
|
||||
"description": "Axepta payment module for Thelia",
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "Axepta"
|
||||
}
|
||||
}
|
||||
52
local/modules/Axepta/templates/backOffice/default/module-configuration.html
Executable file
52
local/modules/Axepta/templates/backOffice/default/module-configuration.html
Executable file
@@ -0,0 +1,52 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12 general-block-decorator">
|
||||
<div class="row">
|
||||
<div class="col-md-12 title title-without-tabs">
|
||||
{intl d='axepta.bo.default' l="Axepta Configuration"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{form name="axepta_configuration"}
|
||||
<form action="{url path="/admin/module/axepta/configure"}" method="post">
|
||||
{form_hidden_fields}
|
||||
|
||||
{include file = "includes/inner-form-toolbar.html"
|
||||
hide_flags = true
|
||||
page_url = "{url path='/admin/module/Axepta'}"
|
||||
close_url = "{url path='/admin/modules'}"
|
||||
}
|
||||
|
||||
{if $form_error}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<p class="title title-without-tabs">{intl d='axepta.bo.default' l="Access to Axepta Platform"}</p>
|
||||
{render_form_field field="merchant_id"}
|
||||
{render_form_field field="hmac"}
|
||||
{render_form_field field="crypt_key"}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="title title-without-tabs">{intl d='axepta.bo.default' l="Payment configuration"}</p>
|
||||
{render_form_field field="send_confirmation_message_only_if_paid"}
|
||||
{render_form_field field="run_mode"}
|
||||
{render_form_field field="allowed_ip_list"}
|
||||
{render_form_field field="minimum_amount"}
|
||||
{render_form_field field="maximum_amount"}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/form}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
{* We shoud use the "GET" method fo rsome fields to be properly processed byt the gateway *}
|
||||
{* see https://docs.axepta.bnpparibas/display/DOCBNP/Payment+page#Paymentpage-Howtocallthepaymentmethodsselectionpage? *}
|
||||
<script type="text/javascript">
|
||||
jQuery(function($) {
|
||||
var $form = $('#payement_gateway_form');
|
||||
|
||||
$form.attr('method', 'get');
|
||||
$form.submit();
|
||||
|
||||
$('#force-submit-payment-form').click(function(ev) {
|
||||
$form.submit();
|
||||
|
||||
ev.preventDefault();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user