Mercanet files integration
This commit is contained in:
parent
b887bec932
commit
0f901fa7aa
6 changed files with 894 additions and 0 deletions
|
|
@ -44,3 +44,7 @@ PUSHER_APP_CLUSTER=mt1
|
|||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
MERCANET_SECRET=
|
||||
MERCANET_MERCHAND_ID=
|
||||
MERCANET_ENV=TEST
|
||||
|
|
|
|||
55
app/Enums/Mercanet/PaymentResponse.php
Normal file
55
app/Enums/Mercanet/PaymentResponse.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Mercanet;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self ok()
|
||||
* Situation normale suivie du processus normal d'affichage des pages de paiement.
|
||||
* @method static self invalidIds()
|
||||
* L’identifiant commerçant ou le contrat acquéreur sont invalides.
|
||||
* @method static self invalidParameters()
|
||||
* Les paramètres de la transaction sont invalides. Vérifiez les paramètres de la requête.
|
||||
* @method static self invalidRequestFormat()
|
||||
* Le format de la requête est invalide.
|
||||
* @method static self securityIssue()
|
||||
* Problème de sécurité, par ex. le sceau calculé est incorrect.
|
||||
* @method static self transactionAlreadyExists()
|
||||
* La transaction existe déjà.
|
||||
* @method static self unreachableService()
|
||||
* Service temporairement indisponible
|
||||
* @method static self internalIssue()
|
||||
* (interne à la classe) = Pb appel cUrl
|
||||
*/
|
||||
final class PaymentResponse extends BaseEnum
|
||||
{
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'ok' => '00',
|
||||
'invalidIds' => '03',
|
||||
'invalidParameters' => '12',
|
||||
'invalidRequestFormat' => '30',
|
||||
'securityIssue' => '34',
|
||||
'transactionAlreadyExists' => '94',
|
||||
'unreachableService' => '99',
|
||||
'internalIssue' => '500'
|
||||
];
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'ok' => 'Situation normale suivie du processus normal d\'affichage des pages de paiement.',
|
||||
'invalidIds' => 'L’identifiant commerçant ou le contrat acquéreur sont invalides.',
|
||||
'invalidParameters' => 'Les paramètres de la transaction sont invalides. ' .
|
||||
'Vérifiez les paramètres de la requête.',
|
||||
'invalidRequestFormat' => 'Le format de la requête est invalide.',
|
||||
'securityIssue' => 'Problème de sécurité, par ex. le sceau calculé est incorrect.',
|
||||
'transactionAlreadyExists' => 'La transaction existe déjà.',
|
||||
'unreachableService' => 'Service temporairement indisponible',
|
||||
'internalIssue' => 'Erreur interne, eg: probleme appel CURL'
|
||||
];
|
||||
}
|
||||
}
|
||||
53
app/Enums/Mercanet/RedirectionStatusCode.php
Normal file
53
app/Enums/Mercanet/RedirectionStatusCode.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Mercanet;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self redirect()
|
||||
* Ce cas doit être suivi de la redirection de l’utilisateur vers la page de paiement.
|
||||
*
|
||||
* @method static self requestError03()
|
||||
* @method static self requestError12()
|
||||
* @method static self requestError30()
|
||||
* @method static self requestError34()
|
||||
* Ces codes d’erreur indiquent que la requête comporte un problème qui doit être résolu.
|
||||
* Le processus de paiement doit alors être interrompu.
|
||||
*
|
||||
* @method static self referenceAlreadyUsed()
|
||||
* La référence de transaction a déjà été utilisée.
|
||||
* Le commerçant doit réessayer avec une autre référence de transaction.
|
||||
*
|
||||
* @method static self serviceDisponibiltyIssue()
|
||||
* Problème de disponibilité du service de paiement. Le commerçant doit essayer de renvoyer la requête.
|
||||
* Il convient d’utiliser une nouvelle référence de transaction pour éviter un code de réponse 94.
|
||||
*/
|
||||
final class RedirectionStatusCode extends BaseEnum
|
||||
{
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'redirect' => '00',
|
||||
'requestError03' => '03',
|
||||
'requestError12' => '12',
|
||||
'requestError30' => '30',
|
||||
'requestError34' => '34',
|
||||
'referenceAlreadyUsed' => '94',
|
||||
'serviceDisponibiltyIssue' => '99',
|
||||
];
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'redirect' => 'Redirection Acceptée',
|
||||
'requestError03' => 'Problème de request code 03',
|
||||
'requestError12' => 'Problème de request code 12',
|
||||
'requestError30' => 'Problème de request code 30',
|
||||
'requestError34' => 'Problème de request code 34',
|
||||
'referenceAlreadyUsed' => 'La référence de transaction à déja été utilisée',
|
||||
'serviceDisponibiltyIssue' => 'Problème de disponibilité du service de paiement',
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Enums/Mercanet/TransactionResponse.php
Normal file
42
app/Enums/Mercanet/TransactionResponse.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Mercanet;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self accepted()
|
||||
* Paiement accepté
|
||||
* @method static self refused()
|
||||
* Paiement refusé
|
||||
* @method static self fraud()
|
||||
* Paiement refusé pour fraude
|
||||
* @method static self maxReached()
|
||||
* Paiement refusé pour nombre max essais atteint
|
||||
* @method static self technicalIssue()
|
||||
* Paiement refusé pour problème technique
|
||||
*/
|
||||
final class TransactionResponse extends BaseEnum
|
||||
{
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'accepted' => '00',
|
||||
'refused' => '05',
|
||||
'fraud' => '34',
|
||||
'maxReached' => '75',
|
||||
'technicalIssue' => '90'
|
||||
];
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'accepted' => 'Paiement accepté',
|
||||
'refused' => 'Paiement refusé',
|
||||
'fraud' => 'Paiement refusé pour fraude',
|
||||
'maxReached' => 'Paiement refusé pour nombre max essais atteint',
|
||||
'technicalIssue' => 'Paiement refusé pour problème technique'
|
||||
];
|
||||
}
|
||||
}
|
||||
732
app/Lib/Mercanet/Mercanet.php
Normal file
732
app/Lib/Mercanet/Mercanet.php
Normal file
|
|
@ -0,0 +1,732 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Mercanet;
|
||||
|
||||
use BadMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
use Normalizer;
|
||||
|
||||
class Mercanet
|
||||
{
|
||||
public const TEST = "https://payment-webinit-mercanet.test.sips-atos.com/rs-services/v2/paymentInit";
|
||||
public const SIMULATION = "https://payment-webinit.simu.mercanet.bnpparibas.net/rs-services/v2/paymentInit";
|
||||
public const PRODUCTION = "https://payment-webinit.mercanet.bnpparibas.net/rs-services/v2/paymentInit";
|
||||
|
||||
public const INTERFACE_VERSION = "IR_WS_2.20";
|
||||
public const INSTALMENT = "INSTALMENT";
|
||||
|
||||
// BYPASS3DS
|
||||
public const BYPASS3DS_ALL = "ALL";
|
||||
public const BYPASS3DS_MERCHANTWALLET = "MERCHANTWALLET";
|
||||
|
||||
private $brandsmap = array(
|
||||
'ACCEPTGIRO' => 'CREDIT_TRANSFER',
|
||||
'AMEX' => 'CARD',
|
||||
'BCMC' => 'CARD',
|
||||
'BUYSTER' => 'CARD',
|
||||
'BANK CARD' => 'CARD',
|
||||
'CB' => 'CARD',
|
||||
'IDEAL' => 'CREDIT_TRANSFER',
|
||||
'INCASSO' => 'DIRECT_DEBIT',
|
||||
'MAESTRO' => 'CARD',
|
||||
'MASTERCARD' => 'CARD',
|
||||
'MASTERPASS' => 'CARD',
|
||||
'MINITIX' => 'OTHER',
|
||||
'NETBANKING' => 'CREDIT_TRANSFER',
|
||||
'PAYPAL' => 'CARD',
|
||||
'PAYLIB' => 'CARD',
|
||||
'REFUND' => 'OTHER',
|
||||
'SDD' => 'DIRECT_DEBIT',
|
||||
'SOFORT' => 'CREDIT_TRANSFER',
|
||||
'VISA' => 'CARD',
|
||||
'VPAY' => 'CARD',
|
||||
'VISA ELECTRON' => 'CARD',
|
||||
'CBCONLINE' => 'CREDIT_TRANSFER',
|
||||
'KBCONLINE' => 'CREDIT_TRANSFER'
|
||||
);
|
||||
|
||||
/** @var ShaComposer */
|
||||
private $secretKey;
|
||||
private $env;
|
||||
private $returnUrl;
|
||||
private $automaticUrl = false;
|
||||
|
||||
private $pspURL = self::TEST;
|
||||
|
||||
private $responseData;
|
||||
private $parameters = array();
|
||||
|
||||
private $pspFields = array(
|
||||
'amount', 'cardExpiryDate', 'cardNumber', 'cardCSCValue',
|
||||
'currencyCode', 'merchantId', 'interfaceVersion', 'sealAlgorithm',
|
||||
'transactionReference', 'keyVersion', 'paymentMeanBrand', 'customerLanguage',
|
||||
'billingAddress.city', 'billingAddress.company', 'billingAddress.country',
|
||||
'billingAddress', 'billingAddress.postBox', 'billingAddress.state',
|
||||
'billingAddress.street', 'billingAddress.streetNumber', 'billingAddress.zipCode',
|
||||
'billingContact.email', 'billingContact.firstname', 'billingContact.gender',
|
||||
'billingContact.lastname', 'billingContact.mobile', 'billingContact.phone',
|
||||
'customerAddress', 'customerAddress.city', 'customerAddress.company',
|
||||
'customerAddress.country', 'customerAddress.postBox', 'customerAddress.state',
|
||||
'customerAddress.street', 'customerAddress.streetNumber', 'customerAddress.zipCode',
|
||||
'customerEmail', 'customerContact', 'customerContact.email', 'customerContact.firstname',
|
||||
'customerContact.gender', 'customerContact.lastname', 'customerContact.mobile',
|
||||
'customerContact.phone', 'customerContact.title', 'expirationDate', 'automaticResponseUrl',
|
||||
'templateName', 'paymentMeanBrandList', 'instalmentData.number', 'instalmentData.datesList',
|
||||
'instalmentData.transactionReferencesList', 'instalmentData.amountsList', 'paymentPattern',
|
||||
'captureDay', 'captureMode', 'merchantTransactionDateTime', 'fraudData.bypass3DS', 'seal',
|
||||
'orderChannel', 'orderId', 'returnContext', 'transactionOrigin', 'merchantWalletId', 'paymentMeanId'
|
||||
);
|
||||
|
||||
private $requiredFields = array(
|
||||
'amount', 'currencyCode', 'interfaceVersion', 'keyVersion', 'merchantId', 'normalReturnUrl', 'orderChannel',
|
||||
'transactionReference'
|
||||
);
|
||||
|
||||
public $allowedlanguages = array(
|
||||
'nl', 'fr', 'de', 'it', 'es', 'cy', 'en'
|
||||
);
|
||||
|
||||
private static $currencies = array(
|
||||
'EUR' => '978', 'USD' => '840', 'CHF' => '756', 'GBP' => '826',
|
||||
'CAD' => '124', 'JPY' => '392', 'MXP' => '484', 'TRY' => '949',
|
||||
'AUD' => '036', 'NZD' => '554', 'NOK' => '578', 'BRC' => '986',
|
||||
'ARP' => '032', 'KHR' => '116', 'TWD' => '901', 'SEK' => '752',
|
||||
'DKK' => '208', 'KRW' => '410', 'SGD' => '702', 'XPF' => '953',
|
||||
'XOF' => '952'
|
||||
);
|
||||
|
||||
public static function convertCurrencyToCurrencyCode($currency)
|
||||
{
|
||||
if (!in_array($currency, array_keys(self::$currencies))) {
|
||||
throw new InvalidArgumentException("Unknown currencyCode $currency.");
|
||||
}
|
||||
return self::$currencies[$currency];
|
||||
}
|
||||
|
||||
public static function convertCurrencyCodeToCurrency($code)
|
||||
{
|
||||
if (!in_array($code, array_values(self::$currencies))) {
|
||||
throw new InvalidArgumentException("Unknown Code $code.");
|
||||
}
|
||||
return array_search($code, self::$currencies);
|
||||
}
|
||||
|
||||
public static function getCurrencies()
|
||||
{
|
||||
return self::$currencies;
|
||||
}
|
||||
|
||||
public function __construct($secret, $MerchantId, $env, $returnUrl, $automaticUrl = false)
|
||||
{
|
||||
$this->secretKey = $secret;
|
||||
$this->parameters['merchantId'] = $MerchantId;
|
||||
$this->env = $env;
|
||||
$this->returnUrl = $returnUrl;
|
||||
if ($automaticUrl !== false) {
|
||||
$this->automaticUrl = $automaticUrl;
|
||||
}
|
||||
|
||||
switch ($this->env) {
|
||||
case 'TEST':
|
||||
$this->setUrl(Mercanet::TEST);
|
||||
break;
|
||||
case 'SIMULATION':
|
||||
$this->setUrl(Mercanet::SIMULATION);
|
||||
break;
|
||||
case 'PRODUCTION':
|
||||
$this->setUrl(Mercanet::PRODUCTION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function shaCompose(array $parameters)
|
||||
{
|
||||
$shaString = '';
|
||||
foreach ($parameters as $key => $value) {
|
||||
if ($key != 'keyVersion') {
|
||||
if (is_array($value)) {
|
||||
$shaString .= implode('', $value);
|
||||
} else {
|
||||
$shaString .= $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $shaString;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getShaSign()
|
||||
{
|
||||
$this->validate();
|
||||
return hash_hmac('sha256', utf8_encode($this->shaCompose($this->toArray())), $this->secretKey);
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->pspURL;
|
||||
}
|
||||
|
||||
public function setUrl($pspUrl)
|
||||
{
|
||||
$this->validateUri($pspUrl);
|
||||
$this->pspURL = $pspUrl;
|
||||
}
|
||||
|
||||
public function setNormalReturnUrl($url)
|
||||
{
|
||||
$this->validateUri($url);
|
||||
$this->parameters['normalReturnUrl'] = $url;
|
||||
}
|
||||
|
||||
public function setAutomaticResponseUrl($url)
|
||||
{
|
||||
$this->validateUri($url);
|
||||
$this->parameters['automaticResponseUrl'] = $url;
|
||||
}
|
||||
|
||||
public function setTransactionReference($transactionReference)
|
||||
{
|
||||
if (preg_match('/[^a-zA-Z0-9_-]/', $transactionReference)) {
|
||||
throw new \InvalidArgumentException("TransactionReference cannot contain special characters");
|
||||
}
|
||||
$this->parameters['transactionReference'] = $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 setCurrency($currency)
|
||||
{
|
||||
if (!array_key_exists(strtoupper($currency), self::getCurrencies())) {
|
||||
throw new InvalidArgumentException("Unknown currency");
|
||||
}
|
||||
$this->parameters['currencyCode'] = self::convertCurrencyToCurrencyCode($currency);
|
||||
}
|
||||
|
||||
public function setLanguage($language)
|
||||
{
|
||||
if (!in_array($language, $this->allowedlanguages)) {
|
||||
throw new InvalidArgumentException("Invalid language locale");
|
||||
}
|
||||
$this->parameters['customerLanguage'] = $language;
|
||||
}
|
||||
|
||||
public function setCustomerEmail($email)
|
||||
{
|
||||
$this->parameters['customerEmail'] = $email;
|
||||
}
|
||||
|
||||
public function setPaymentBrands($brands)
|
||||
{
|
||||
$this->parameters['paymentMeanBrandList'] = '';
|
||||
foreach ($brands as $brand) {
|
||||
if (!array_key_exists(strtoupper($brand), $this->brandsmap)) {
|
||||
throw new InvalidArgumentException("Unknown Brand [$brand].");
|
||||
}
|
||||
}
|
||||
$this->parameters['paymentMeanBrandList'] = $brands;
|
||||
}
|
||||
|
||||
public function setBillingContactEmail($email)
|
||||
{
|
||||
if (strlen($email) > 50) {
|
||||
throw new InvalidArgumentException("Email is too long");
|
||||
}
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
throw new InvalidArgumentException("Email is invalid");
|
||||
}
|
||||
$this->parameters['billingContact.email'] = $email;
|
||||
}
|
||||
|
||||
public function setBillingAddressStreet($street)
|
||||
{
|
||||
if (strlen($street) > 35) {
|
||||
throw new InvalidArgumentException("street is too long");
|
||||
}
|
||||
$this->parameters['billingAddress.street'] = Normalizer::normalize($street);
|
||||
}
|
||||
|
||||
public function setBillingAddressStreetNumber($nr)
|
||||
{
|
||||
if (strlen($nr) > 10) {
|
||||
throw new InvalidArgumentException("streetNumber is too long");
|
||||
}
|
||||
$this->parameters['billingAddress.streetNumber'] = Normalizer::normalize($nr);
|
||||
}
|
||||
|
||||
public function setBillingAddressZipCode($zipCode)
|
||||
{
|
||||
if (strlen($zipCode) > 10) {
|
||||
throw new InvalidArgumentException("zipCode is too long");
|
||||
}
|
||||
$this->parameters['billingAddress.zipCode'] = Normalizer::normalize($zipCode);
|
||||
}
|
||||
|
||||
public function setBillingAddressCity($city)
|
||||
{
|
||||
if (strlen($city) > 25) {
|
||||
throw new InvalidArgumentException("city is too long");
|
||||
}
|
||||
$this->parameters['billingAddress.city'] = Normalizer::normalize($city);
|
||||
}
|
||||
|
||||
public function setBillingContactPhone($phone)
|
||||
{
|
||||
if (strlen($phone) > 30) {
|
||||
throw new InvalidArgumentException("phone is too long");
|
||||
}
|
||||
$this->parameters['billingContact.phone'] = $phone;
|
||||
}
|
||||
|
||||
public function setBillingContactFirstname($firstname)
|
||||
{
|
||||
// replace quotes
|
||||
$this->parameters['billingContact.firstname'] = str_replace(
|
||||
array("'", '"'),
|
||||
'',
|
||||
Normalizer::normalize($firstname)
|
||||
);
|
||||
}
|
||||
|
||||
public function setBillingContactLastname($lastname)
|
||||
{
|
||||
// replace quotes
|
||||
$this->parameters['billingContact.lastname'] = str_replace(
|
||||
array("'", '"'),
|
||||
'',
|
||||
Normalizer::normalize($lastname)
|
||||
);
|
||||
}
|
||||
|
||||
public function setCaptureDay($number)
|
||||
{
|
||||
if (strlen($number) > 2) {
|
||||
throw new InvalidArgumentException("captureDay is too long");
|
||||
}
|
||||
$this->parameters['captureDay'] = $number;
|
||||
}
|
||||
|
||||
public function setCaptureMode($value)
|
||||
{
|
||||
if (strlen($value) > 20) {
|
||||
throw new InvalidArgumentException("captureMode is too long");
|
||||
}
|
||||
$this->parameters['captureMode'] = $value;
|
||||
}
|
||||
|
||||
public function setMerchantTransactionDateTime($value)
|
||||
{
|
||||
if (strlen($value) > 25) {
|
||||
throw new InvalidArgumentException("merchantTransactionDateTime is too long");
|
||||
}
|
||||
$this->parameters['merchantTransactionDateTime'] = $value;
|
||||
}
|
||||
|
||||
public function setInterfaceVersion($value)
|
||||
{
|
||||
$this->parameters['interfaceVersion'] = $value;
|
||||
}
|
||||
|
||||
public function setSealAlgorithm($value)
|
||||
{
|
||||
$this->parameters['sealAlgorithm'] = $value;
|
||||
}
|
||||
|
||||
public function setOrderChannel($value)
|
||||
{
|
||||
if (strlen($value) > 20) {
|
||||
throw new InvalidArgumentException("orderChannel is too long");
|
||||
}
|
||||
$this->parameters['orderChannel'] = $value;
|
||||
}
|
||||
|
||||
public function setOrderId($value)
|
||||
{
|
||||
if (strlen($value) > 32) {
|
||||
throw new InvalidArgumentException("orderId is too long");
|
||||
}
|
||||
$this->parameters['orderId'] = $value;
|
||||
}
|
||||
|
||||
public function setReturnContext($value)
|
||||
{
|
||||
if (strlen($value) > 255) {
|
||||
throw new InvalidArgumentException("returnContext is too long");
|
||||
}
|
||||
$this->parameters['returnContext'] = $value;
|
||||
}
|
||||
|
||||
public function setTransactionOrigin($value)
|
||||
{
|
||||
if (strlen($value) > 20) {
|
||||
throw new InvalidArgumentException("transactionOrigin is too long");
|
||||
}
|
||||
$this->parameters['transactionOrigin'] = $value;
|
||||
}
|
||||
|
||||
// Methodes liees a la carte
|
||||
public function setCardNumber($number)
|
||||
{
|
||||
if (strlen($number) > 19) {
|
||||
throw new InvalidArgumentException("cardNumber is too long");
|
||||
}
|
||||
if (strlen($number) < 12) {
|
||||
throw new InvalidArgumentException("cardNumber is too short");
|
||||
}
|
||||
$this->parameters['cardNumber'] = $number;
|
||||
}
|
||||
|
||||
public function setCardExpiryDate($date)
|
||||
{
|
||||
if (strlen($date) != 6) {
|
||||
throw new InvalidArgumentException("cardExpiryDate value is invalid");
|
||||
}
|
||||
$this->parameters['cardExpiryDate'] = $date;
|
||||
}
|
||||
|
||||
public function setCardCSCValue($value)
|
||||
{
|
||||
if (strlen($value) > 4) {
|
||||
throw new InvalidArgumentException("cardCSCValue value is invalid");
|
||||
}
|
||||
$this->parameters['cardCSCValue'] = $value;
|
||||
}
|
||||
|
||||
// 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 setPaymentMeanId($value)
|
||||
{
|
||||
if (strlen($value) > 6) {
|
||||
throw new InvalidArgumentException("paymentMeanId is too long");
|
||||
}
|
||||
$this->parameters['paymentMeanId'] = $value;
|
||||
}
|
||||
|
||||
// Methodes liees au paiement en n-fois
|
||||
|
||||
public function setInstalmentDataNumber($number)
|
||||
{
|
||||
if (strlen($number) > 2) {
|
||||
throw new InvalidArgumentException("instalmentData.number is too long");
|
||||
}
|
||||
if (($number < 2) || ($number > 50)) {
|
||||
throw new InvalidArgumentException(
|
||||
"instalmentData.number invalid value : value must be set between 2 and 50"
|
||||
);
|
||||
}
|
||||
$this->parameters['instalmentData.number'] = $number;
|
||||
}
|
||||
|
||||
public function setInstalmentDatesList($datesList)
|
||||
{
|
||||
$this->parameters['instalmentData.datesList'] = $datesList;
|
||||
}
|
||||
|
||||
public function setInstalmentDataTransactionReferencesList($transactionReferencesList)
|
||||
{
|
||||
$this->parameters['instalmentData.transactionReferencesList'] = $transactionReferencesList;
|
||||
}
|
||||
|
||||
public function setInstalmentDataAmountsList($amountsList)
|
||||
{
|
||||
$this->parameters['instalmentData.amountsList'] = $amountsList;
|
||||
}
|
||||
|
||||
public function setPaymentPattern($paymentPattern)
|
||||
{
|
||||
$this->parameters['paymentPattern'] = $paymentPattern;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (substr($method, 0, 3) == 'set') {
|
||||
$field = lcfirst(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));
|
||||
if (array_key_exists($field, $this->parameters)) {
|
||||
return $this->parameters[$field];
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadMethodCallException("Unknown method $method");
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
ksort($this->parameters);
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
public function toParameterString()
|
||||
{
|
||||
ksort($this->parameters);
|
||||
$seal = $this->getShaSign();
|
||||
$tmp = array_merge($this->parameters, ['seal' => $seal]);
|
||||
return json_encode($tmp, JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
/*
|
||||
if (substr($val, 0, 1) == "[")
|
||||
$chaine .= '"'.$key.'":'.$val;
|
||||
else
|
||||
$chaine .= '"'.$key.'":"'.$val.'"'; */
|
||||
|
||||
/** @return PaymentRequest */
|
||||
/* public static function createFromArray(ShaComposer $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 de Mercanet
|
||||
// -----------------------------------
|
||||
|
||||
/** @var string */
|
||||
public const SHASIGN_FIELD = "SEAL";
|
||||
|
||||
/** @var string */
|
||||
public 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;
|
||||
|
||||
private $responseRequest;
|
||||
private $responseStatus;
|
||||
private $parameterArray;
|
||||
|
||||
/**
|
||||
* Filter http request parameters
|
||||
* @param array $requestParameters
|
||||
*/
|
||||
private function filterRequestParameters(array $httpRequest)
|
||||
{
|
||||
//filter request for Sips parameters
|
||||
if (!array_key_exists(self::DATA_FIELD, $httpRequest) || $httpRequest[self::DATA_FIELD] == '') {
|
||||
throw new InvalidArgumentException('Data parameter not present in parameters.');
|
||||
}
|
||||
$parameters = array();
|
||||
$this->responseData = $httpRequest[self::DATA_FIELD];
|
||||
$dataString = $httpRequest[self::DATA_FIELD];
|
||||
$this->dataString = $dataString;
|
||||
$dataParams = explode('|', $dataString);
|
||||
foreach ($dataParams as $dataParamString) {
|
||||
$dataKeyValue = explode('=', $dataParamString, 2);
|
||||
$parameters[$dataKeyValue[0]] = $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];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the response is valid
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
$resultat = false;
|
||||
|
||||
$signature = $this->responseData;
|
||||
$compute = hash('sha256', utf8_encode($signature . $this->secretKey));
|
||||
if (strcmp($this->shaSign, $compute) == 0) {
|
||||
// phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
|
||||
if (
|
||||
(strcmp($this->parameters['responseCode'], "00") == 0) ||
|
||||
(strcmp($this->parameters['responseCode'], "60") == 0)
|
||||
) {
|
||||
$resultat = true;
|
||||
}
|
||||
}
|
||||
return $resultat;
|
||||
}
|
||||
|
||||
public function getXmlValueByTag($inXmlset, $needle)
|
||||
{
|
||||
$resource = xml_parser_create(); //Create an XML parser
|
||||
xml_parse_into_struct($resource, $inXmlset, $outArray); // Parse XML data into an array structure
|
||||
xml_parser_free($resource); //Free an XML parser
|
||||
for ($i = 0; $i < count($outArray); $i++) {
|
||||
if ($outArray[$i]['tag'] == strtoupper($needle)) {
|
||||
$tagValue = $outArray[$i]['value'];
|
||||
}
|
||||
}
|
||||
return $tagValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a response parameter
|
||||
* @param string $param
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getParam($key)
|
||||
{
|
||||
return $this->parameterArray[$key];
|
||||
}
|
||||
|
||||
public function getResponseRequest()
|
||||
{
|
||||
return $this->responseRequest;
|
||||
}
|
||||
|
||||
public function executeRequest()
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $this->getUrl());
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->toParameterString());
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Accept:application/json'));
|
||||
curl_setopt($ch, CURLOPT_PORT, 443);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$result = curl_exec($ch); // $this->responseRequest et $this->responseStatus = false;
|
||||
$info = curl_getinfo($ch);
|
||||
|
||||
if (!$result) {
|
||||
error_log(
|
||||
"MERCANET [" . $this->parameters['transactionReference'] . "] : curl error: " . curl_error($ch)
|
||||
);
|
||||
curl_close($ch);
|
||||
return (object)['status' => 'KO', 'code' => 500];
|
||||
}
|
||||
|
||||
if ($info['http_code'] != 200) {
|
||||
error_log(
|
||||
"MERCANET [" . $this->parameters['transactionReference'] .
|
||||
"] : service error: " . $info['http_code'] . " - Return : " . $result
|
||||
);
|
||||
curl_close($ch);
|
||||
return (object)['status' => 'KO', 'code' => 500];
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
if (strlen($result) == 0) {
|
||||
error_log("MERCANET [" . $this->parameters['transactionReference'] . "] : service did not sent back data");
|
||||
return (object)['status' => 'KO', 'code' => 500];
|
||||
}
|
||||
$result_array = json_decode($result);
|
||||
if (isset($result_array->redirectionStatusCode)) {
|
||||
if ($result_array->redirectionStatusCode === '00') {
|
||||
return (object)[
|
||||
'status' => 'OK', 'code' => $result_array->redirectionStatusCode,
|
||||
'url' => $result_array->redirectionUrl, 'version' => $result_array->redirectionVersion,
|
||||
'data' => $result_array->redirectionData
|
||||
];
|
||||
} else {
|
||||
return (object)['status' => 'KO', 'code' => $result_array->redirectionStatusCode, 'message' => $result_array->redirectionStatusMessage];
|
||||
}
|
||||
} else {
|
||||
error_log("MERCANET [" . $this->parameters['transactionReference'] . "] : redirectionStatusCode missing");
|
||||
return (object)['status' => 'KO', 'code' => 500];
|
||||
}
|
||||
}
|
||||
|
||||
public function quickPayment($amount, $ref)
|
||||
{
|
||||
//$this->setUrl($this->env === 'production' ? Mercanet::PRODUCTION : Mercanet::TEST);
|
||||
// Required fields
|
||||
$this->setInterfaceVersion(Mercanet::INTERFACE_VERSION);
|
||||
$this->setKeyVersion('1');
|
||||
$this->setCurrency('EUR');
|
||||
$this->setOrderChannel("INTERNET");
|
||||
// Variables
|
||||
$this->setAmount($amount);
|
||||
$this->setTransactionReference($ref);
|
||||
$this->setNormalReturnUrl($this->returnUrl);
|
||||
if ($this->automaticUrl !== false) {
|
||||
$this->setAutomaticResponseUrl($this->automaticUrl);
|
||||
}
|
||||
// Optional fields
|
||||
$this->setPaymentBrands(['CB', 'VISA', 'MASTERCARD']);
|
||||
$this->setCaptureMode('IMMEDIATE');
|
||||
// Validate
|
||||
$this->validate();
|
||||
|
||||
return $this->executeRequest();
|
||||
}
|
||||
}
|
||||
8
config/mercanet.php
Normal file
8
config/mercanet.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'secret' => env('MERCANET_SECRET'),
|
||||
'merchantId' => env('MERCANET_MERCHAND_ID'),
|
||||
// eg: TEST, SIMULATION, PRODUCTION
|
||||
'env' => env('MERCANET_ENV', 'TEST'),
|
||||
];
|
||||
Loading…
Add table
Reference in a new issue