Pour toute question, nous sommes à un clic

Poser une question

Web SDK Payment

Description

Bibliothèque JavaScript pour afficher le formulaire de paiement sur la page du marchand. Cette méthode convient aux marchands ayant un niveau de conformité aux exigences PCI DCC élevé ou faible.

Scénario de fonctionnement :

  1. Le marchand enregistre la commande via REST API dans la passerelle de paiement
  2. Le mdOrder obtenu (numéro de commande) est transmis par le marchand à la page où cette bibliothèque js est utilisée

Web SDK offre la possibilité d'ajouter sur sa page de paiement des champs de saisie de données de paiement via iframe directement depuis la passerelle de paiement. La sécurité de transmission des données est assurée par le chiffrement du protocole HTTPS.

Avantages :

Inconvénients :

La bibliothèque aide à la collecte des données de carte, leur validation et vérification, la réalisation du paiement et la redirection automatique de l'acheteur vers la page finale via le returnUrl spécifié dans les paramètres.

Comment utiliser

Connecter le script

Environnement de test

<script src="https://dev.bpcbt.com/payment/modules/multiframe/main.js"></script>

Environnement de production

<script src="https://dev.bpcbt.com/payment/modules/multiframe/main.js"></script>

Préparation

Tout d'abord, il est nécessaire de créer un formulaire HTML pour accepter les paiements. Le formulaire doit contenir les blocs #pan, #expiry, #cvc et le bouton #pay. Il n'est pas obligatoire d'utiliser exactement ces noms de champs. Vous pourrez configurer les noms dont vous avez besoin lors de l'initialisation.

Exemple de formulaire HTML qui ne prend pas en charge les liaisons :

<div class="card-body">
    <div class="col-12">
        <label for="pan" class="form-label">Card number</label>
        <!-- Container for card number field -->
        <div id="pan" class="form-control"></div>
    </div>
    <div class="col-6 col-expiry">
        <label for="expiry" class="form-label">Expiry</label>
        <!-- Container for expiry card field -->
        <div id="expiry" class="form-control"></div>
    </div>
    <div class="col-6 col-cvc">
        <label for="cvc" class="form-label">CVC / CVV</label>
        <!-- Container for CVC/CVV field -->
        <div id="cvc" class="form-control"></div>
    </div>
</div>
<!-- Pay button -->
<button class="btn btn-primary btn-lg" type="submit" id="pay">
    <!-- Payment loader -->
    <span class="spinner-border spinner-border-sm visually-hidden" id="pay-spinner"></span>
    <span>Pay</span>
</button>
<!-- Container for errors -->
<div class="error my-2 text-center text-danger visually-hidden" id="error"></div>

Si vous utilisez les liaisons, vous devez inclure un bloc HTML supplémentaire : #select-binding.

Voici un exemple de formulaire HTML qui prend en charge les liaisons :

<div class="card-body">
    <div class="col-12" id="select-binding-container" style="display: none">
        <!-- Select for bindings -->
        <select class="form-select" id="select-binding" aria-label="Default select example">
            <option selected value="new_card">Pay with a new card</option>
        </select>
    </div>
    <div class="col-12">
        <label for="pan" class="form-label">Card number</label>
        <!-- Container for card number field -->
        <div id="pan" class="form-control"></div>
    </div>
    <div class="col-6 col-expiry">
        <label for="expiry" class="form-label">Expiry</label>
        <!-- Container for expiry card field -->
        <div id="expiry" class="form-control"></div>
    </div>
    <div class="col-6 col-cvc">
        <label for="cvc" class="form-label">CVC / CVV</label>
        <!-- Container for cvc/cvv field -->
        <div id="cvc" class="form-control"></div>
    </div>
    <label class="col-12" id="save-card-container">
        <!-- Save card checkbox -->
        <input class="form-check-input" type="checkbox" value="" id="save-card" />
        Save card
    </label>
</div>
<!-- Pay button -->
<button class="btn btn-primary btn-lg" type="submit" id="pay">
    <!-- Payment loader -->
    <span class="spinner-border spinner-border-sm visually-hidden" id="pay-spinner"></span>
    <span>Pay</span>
</button>
<!-- Container for errors -->
<div class="error my-2 text-center text-danger visually-hidden" id="error"></div>

Vous pouvez ajouter au formulaire tous les champs supplémentaires, tels que Cardholder name (nom du porteur de carte), Email (courrier électronique), Phone (numéro de téléphone) etc. Cependant, n'oubliez pas de les transmettre ultérieurement dans la méthode doPayment().

Initialisation du Web SDK

Description du formulaire de paiement

Vous devez exécuter la fonction constructeur new window.PaymentForm().

window.PaymentForm() peut accepter les propriétés suivantes :

Propriétés d'initialisation PaymentForm

mdOrder string required
Identifiant de commande

Description des champs dans le formulaire

apiContext string optional
Contexte (partie de l'URL de la passerelle de paiement après le domaine) pour les requêtes API.
Par défaut, apiContext est automatiquement extrait du lien utilisé pour connecter le script modules/multiframe/main.js.

language string optional
Langue utilisée pour la localisation des erreurs et des placeholders.
Valeur par défaut : en.

autofocus boolean optional
Commutation automatique du focus lors du remplissage des champs.
Valeur par défaut - true

shouldMaskPan boolean optional
Masquer le champ de saisie Pan.
Par défaut false

shouldMaskExpiry boolean optional
Masquer le champ de saisie Expiry.
Par défaut false

shouldMaskCvc boolean optional
Masquer le champ de saisie CVC.
Par défaut true

showPanIcon boolean optional
Afficher l'icône du système de paiement.
Par défaut true

panIconStyle CSSStyleDeclaration optional
Styles personnalisés pour l'icône du système de paiement

Styles généraux pour les champs de saisie

Styles personnalisés pour chacun des champs de saisie (pan, expiry, cvc)

containerClassName string optional
Nom de classe défini en plus pour le conteneur.
Valeur par défaut : field-container

onFormValidate (result: boolean) => void optional
Callback pour traiter le changement de validation du formulaire.
Par exemple :
onFormValidate: (isValid) => {
    alert(isValid ? 'Congratulations!' : 'Oops! We regret.'); 
}

Exemple d'initialisation Web SDK

const webSdkPaymentForm = new window.PaymentForm({
  // Numéro de commande (l'enregistrement de commande se fait avant l'initialisation du formulaire)
  mdOrder: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  // Nom de classe qui sera défini pour les conteneurs avec les champs de saisie
  containerClassName: "field-container",
  onFormValidate: (isValid) => {
    // Traitement de la validation du formulaire
  },
  // Contexte pour les requêtes API
  apiContext: "/payment",
  // Langue - utilisée pour la localisation des erreurs et des noms de placeholders.
  // La langue doit être supportée dans les paramètres du Marchand
  language: "en",
  // Basculer automatiquement le focus lors du remplissage des champs
  autoFocus: true,
  // Afficher l'icône du système de paiement
  showPanIcon: true,
  // Styles personnalisés pour l'icône du système de paiement
  panIconStyle: {
    height: "16px",
    top: "calc(50% - 8px)",
    right: "8px",
  },
  fields: {
    pan: {
      container: document.querySelector("#pan"),
      onFocus: (containerElement) => {
        // Action lors de l'obtention du focus par le champ
        // (containerElement contient la référence à l'élément-conteneur du champ)
      },
      onBlur: (containerElement) => {
        // Action lors de la perte du focus par le champ
        // (containerElement contient la référence à l'élément-conteneur du champ)
      },
      onValidate: (isValid, containerElement) => {
        // Action lors de la validation du champ
        // (isValid est égal à true si le champ est valide, sinon false)
        // (containerElement contient la référence à l'élément-conteneur du champ)
      },
    },
    expiry: {
      container: document.querySelector("#expiry"),
      // ...
    },
    cvc: {
      container: document.querySelector("#cvc"),
      // ...
    },
  },
  // Styles pour les champs de saisie
  styles: {
    // État de base
    base: {
      color: "black",
      padding: '0px 16px',
      fontSize: '18px',
      fontFamily: 'monospace',
    },
    // État avec focus
    focus: {
      color: "blue",
    },
    // État désactivé
    disabled: {
      color: "gray",
    },
    // Avec valeur valide
    valid: {
      color: "green",
    },
    // Avec valeur invalide
    invalid: {
      color: "red",
    },
    // Style pour le placeholder
    placeholder: {
      // Style de base
      base: {
        color: "gray",
      },
      // Style lors du focus
      focus: {
        color: "transparent",
      },
    },
  },
});

Méthode destroy

La méthode destroy() dans Web SDK est utilisée pour supprimer toutes les ressources et les écouteurs d'événements liés à une instance spécifique de Web SDK. Lorsque vous appelez la méthode destroy(), elle nettoie tous les écouteurs d'événements et les conteneurs de champs de saisie qui ont été créés par Web SDK au cours de son cycle de vie. Ceci est utile lorsque vous n'avez plus besoin de l'instance Web SDK.

La méthode destroy() exécute généralement les tâches suivantes :

  1. Supprime tous les écouteurs d'événements qui ont été ajoutés à l'instance Web SDK.
  2. Nettoie tous les conteneurs de champs de saisie créés.

Exemple de méthode destroy

document.querySelector("#destroy").addEventListener("click", function () {
  webSdkPaymentForm.destroy();
});

Stylisation

La stylisation des conteneurs dans lesquels sont transmis les champs de saisie est définie de manière autonome selon le design de votre page. Différents états des conteneurs de champ de saisie peuvent être stylisés à l'aide des classes CSS suivantes :

Le paramètre className est défini lors de l'initialisation via le paramètre containerClassName dans les propriétés window.PaymentForm().

Exemple :

<style>

      .field-container {
        width: 100%;
        height: 50px;
        padding: 0;
      }

      .field-container--focus {
        border-color: #86b7fe;
        outline: 0;
        box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
      }

      .field-container--valid {
        border-color: #198754;
      }
      .field-container--valid.field-container--focus {
        box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
      }

      .field-container--invalid {
        border-color: #dc3545;
      }
      .field-container--invalid.field-container--focus {
        box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
      }

  </style>
  <script>
      //...
        const paymentForm = new window.PaymentForm({
          //...
          containerClassName: 'field-container',
          //...

  </script>

Polices

Dans Web SDK, il est possible d'utiliser des polices système/préinstallées sur les appareils. La police est définie lors de l'initialisation Web SDK dans la propriété styles ou customStyles. Par exemple dans styles.base.fontFamily.

Stylisation des champs de saisie

Vous pouvez personnaliser l'apparence des champs de saisie. Pour cela

Exemple :

const webSdkPaymentForm = new window.PaymentForm({
      // ...
      // styles par défaut pour tous les champs de saisie
      styles: {
        base: {
          color: 'black',
          padding: '0px 16px',
          fontSize: '18px',
          fontFamily: 'Arial, sans-serif',
        },
        // ...
        invalid: {
          color: 'red',
        },
        // ...
      },
      // styles personnalisés pour le champ de saisie du numéro de carte
      customStyles: {
        pan: {
          base: {
            color: 'blue',
            padding: '0px 24px',
            fontSize: '22px',
          },
          invalid: {
              color: 'orange',
          },
        },
      },
    });

Paramètres supplémentaires

Configurez des paramètres supplémentaires lors de l'initialisation, tels que la langue placeholder, les icônes des systèmes de paiement, le masquage des champs de saisie, etc. La liste complète des paramètres est disponible dans Propriétés d'initialisation PaymentForm.

Validation

WebSDK assure la vérification, la validation et la protection uniquement des champs de saisie principaux requis pour effectuer le paiement : Pan, Expiry, CVC.

Tous les autres champs supplémentaires, tels que Cardholder name, Phone, Email, les champs assurant l'exécution des exigences mandat Visa Secure Data etc., le marchand doit les valider de manière autonome de son côté.

Exemples d'expressions régulières pour la validation de champs supplémentaires :

Cardholder name:

// regex: ^[A-zÁÉÍÑÓÚÜáéíñóúü][A-zÁÉÍÑÓÚÜáéíñóúü'\.\s]* [A-zÁÉÍÑÓÚÜáéíñóúü][A-zÁÉÍÑÓÚÜáéíñóúü'\.\s]*$

export function validateCardholderName({
    errorMessage = 'Invalid cardholder'
} = {}) {
    return (value) => {
        const regex = /^[A-zÁÉÍÑÓÚÜáéíñóúü][A-zÁÉÍÑÓÚÜáéíñóúü'\.\s]* [A-zÁÉÍÑÓÚÜáéíñóúü][A-zÁÉÍÑÓÚÜáéíñóúü'\.\s]*$/;
        return regex.test(String(value).trim()) ? null : errorMessage;
    };
}

Email:

// regex: ^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$

export function validateEmail({
    errorMessage = 'Invalid email'
} = {}) {
    return (value) => {
        const regex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
        return regex.test(String(value).toLowerCase()) ? null : errorMessage;
    };
}

Phone:

// regex: ^\+\d{7,15}$

export function validatePhone({
    errorMessage = 'Invalid phone number'
} = {}) {
    return (value) => {
        const regex = /^\+\d{7,15}$/;
        return regex.test(String(value).trim()) ? null : errorMessage;
    };
}

Paiement sans carte sauvegardée (liaison)

Étape 1. Exécuter la méthode d'initialisation

Après avoir défini les paramètres du Web SDK, il est nécessaire d'appeler init(). Cette fonction retourne un callback, où vous pouvez, par exemple, masquer le chargeur ou faire autre chose. init() retourne c.

Par exemple :

webSdkFormWithoutBindings
  .init()
  .then((success) => {
    console.log('success', success)
    // Script initialisé avec succès. Promise retourne un objet contenant des informations utiles sur la commande enregistrée 
    // dans la passerelle de paiement. Après cela, vous pouvez retirer le loader ou effectuer d'autres actions :
    document
      .querySelector(".payment-form-loader")
      .classList.remove("payment-form-loader--active");
  })
  .catch((error) => {
    // Des erreurs se sont produites lors de l'initialisation du script. L'exécution ultérieure est impossible.
    // Promise retourne un message d'erreur que nous pouvons afficher sur la page :
    const errorEl = document.querySelector('#error_1');
    errorEl.innerHTML = e.message;
    errorEl.classList.remove('visually-hidden');
  })
  .finally(() => {
    // Actions exécutées après l'initialisation, indépendamment de son exécution réussie ou non. 
  });

Étape 2. Traitement du clic sur le bouton de paiement. Exécuter la méthode de paiement

Pour effectuer le paiement, appelez la fonction doPayment(). Il n'est pas nécessaire d'envoyer les données de la carte, le Web SDK le fera. doPayment() retourne une Promise.

La méthode accepte les paramètres suivants :

phone String optional
Numéro de téléphone du client

email String optional
Email du client

cardholderName String optional
Nom du porteur de la carte.

jsonParams Object optional
Champs supplémentaires. Par exemple, vous pouvez envoyer des informations supplémentaires sur la commande ou toute autre information utile pour vous. Par exemple, jsonParams: { "t-shirt-color": "noir", "size": "M" }

Mise à jour du mandat Visa Secure Data Field

Veuillez noter les exigences IPS Visa concernant les champs de données supplémentaires nécessaires pour les demandes d'authentification EMV 3DS. Les marchands doivent fournir des données de transaction complètes et précises dans leurs demandes d'authentification. Les marchands doivent également garantir que l'URL de la méthode 3DS effectue la collecte de données d'appareil pour soutenir une authentification réussie dans le cas où l'URL de la méthode 3DS est fournie par l'émetteur.

Ainsi, la collecte de champs supplémentaires pour VISA est de la responsabilité du marchand. Vous pouvez consulter le texte complet des exigences dans Visa Secure Data Field Mandate.

Les champs supplémentaires sont transmis comme propriétés de l'objet, qui est l'argument de la fonction doPayment().

Exemple d'appel :

webSdkFormWithoutBindings
  .doPayment({
    // Paramètres supplémentaires
    email: "foo@bar.com",
    phone: "4420123456789",
    cardholderName: "JOHN DOE",
    jsonParams: { foo: "bar" },
  })
  .then((result) => {
    console.log("result", result);
  })
  .catch((e) => {
    // Traitement des erreurs. Par exemple, affichons le bloc d'erreur
    errorEl.innerHTML = e.message;
    errorEl.classList.remove("visually-hidden");
  })
  .finally(() => {
    // S'exécute dans tous les cas. Par exemple, rendre le bouton "Payer" à nouveau actif.
    payButton.disabled = false;
    spinnerEl.classList.add("visually-hidden");
  });

Démonstration sans carte sauvegardée

Pour le fonctionnement de Web SDK Payment nécessite Order ID (identifiant de commande enregistré dans la passerelle de paiement).
Pour des fins de travail - enregistrez la commande via API.

Ce formulaire est utilisé uniquement à des fins de démonstration - utilisez la valeur Order ID = xxxxx-xxxxx-xxxxx-xxxxx

Tout le code de démonstration

<div class="container_demo">
    <div class="about">
        <form name="formRunTest">
            <label for="mdOrder"> Order ID (mdOrder) <br>
              <span class="label__desc">(Doit provenir du backend. Cette saisie est destinée uniquement à la démonstration)</span>
            </label>
            <div class="run-test">
                <input id="mdOrder" type="text" placeholder="Paste the mdOrder registered for sandbox"/>
                <button class="btn-mini" id="load" type="submit">Load</button>
            </div>
        </form>
    </div>
    <div class="payment-form">

        <div class="payment-form-loader payment-form-loader--active">
            Web SDK Payment nécessite la présence de mdOrder (commande préalablement enregistrée dans la passerelle).<br>
            Enregistrer une commande est possible via Merchant Portal ou via API. <br><br>
            Ou essayez d'utiliser <code>xxxxx-xxxxx-xxxxx-xxxxx</code> si vous voulez obtenir seulement le formulaire de paiement.
        </div>

        <div class="card-body">
            <div class="col-12">
                <label for="pan" class="form-label">Numéro de carte</label>
                <div id="pan" class="form-control"></div>
            </div>
            <div class="col-6 col-expiry">
                <label for="expiry" class="form-label">Date d'expiration</label>
                <div id="expiry" class="form-control"></div>
            </div>
            <div class="col-6 col-cvc">
                <label for="cvc" class="form-label">CVC / CVV</label>
                <div id="cvc" class="form-control"></div>
            </div>
            <!-- Champs supplémentaires pour Visa Mandatory -->
            <div class="col-12 additional-field" style="display:none;">
              <label for="" class="form-label">Cardholder</label>
              <div id="cardholder" class="additional-field-container">
                  <input type="text" class="additional-field-input" placeholder="Surname"value="JOHN DOE">
              </div>
            </div>
            <div class="col-12 additional-field"  style="display:none;">
                <label for="" class="form-label">Mobile phone</label>
                <div id="mobile" class="additional-field-container">
                    <input type="tel" class="additional-field-input" placeholder="+4915112345" value="+4915112345678">
                </div>
            </div>
            <div class="col-12 additional-field" style="display:none;">
                <label for="" class="form-label">Email address</label>
                <div id="email" class="additional-field-container">
                    <input type="text" class="additional-field-input" placeholder="address@mail" value="address@mail.com">
                </div>
            </div>
        </div>
        <button class="btn btn-primary btn-lg" type="submit" id="pay">
            <span
            class="spinner-border spinner-border-sm me-2 visually-hidden"
            role="status"
            aria-hidden="true"
            id="pay-spinner">
            </span>
            <span>Payer</span>
        </button>
        <!-- Ces boutons ne sont nécessaires que pour la démonstration du fonctionnement de la méthode destroy -->
        <button class="btn btn-secondary" type="button" id="destroyFormWithoutCredentials">
            <span>Détruire</span>
        </button>
        <button class="btn btn-secondary" type="button" id="reinitFormWithoutCredentials" style="display: none;">
            <span>Initialiser</span>
        </button>
        <div class="error my-2 text-center text-danger visually-hidden" id="error"></div>
    </div>
</div>

<script>
document.addEventListener("DOMContentLoaded", () => {
  // Fonction pour l'initialisation du formulaire de paiement avec possibilité de réutilisation après destruction
  function initPaymentForm() {
    const mrOrderInput = document.getElementById("mdOrder");
    mrOrderInput.classList.remove("invalid");
    if (!/(\w+-){3,10}\w+/g.test(mrOrderInput.value)) {
      mrOrderInput.classList.add("invalid");
      return;
    }

    // Initialisation Web SDK. L'identifiant de commande mdOrder est nécessaire.
    initPayment(mrOrderInput.value);
  }

  document.formPageTest.addEventListener("submit", function (e) {
    e.preventDefault();
    // Initialisation du formulaire de paiement
    initPaymentForm();
  });

  let webSdkFormWithoutBindings;
  // Tableau d'objets pour les champs supplémentaires, qui contiennent l'id du champ, son modèle de validation et les caractères autorisés pour la saisie
  const mandatoryFieldsWithoutBinding = [
    {
        id: '#cardholder',
        template: /^[a-zA-Z '`.\-]{4,24}$/,
        replace: /[^a-zA-Z ' \-`.]/g,
    },
    {
        id: '#mobile',
        template: /^\+?[1-9][0-9]{7,14}$/,
        replace: /[^0-9\+]/g,
    },
    {
        id: '#email',
        template: /^[a-zA-Z0-9._-]{1,64}@([a-zA-Z0-9.-]{2,255})\.[a-zA-Z]{2,255}$/,
        replace: /[^a-zA-Z0-9@._-]/g,
    }
  ]

  function initPayment(mdOrder) {
    webSdkFormWithoutBindings = new window.PaymentForm({
      mdOrder: mdOrder,
      onFormValidate: () => {},
      language: "en", // Langue (anglais)
      containerClassName: "field-container",
      autoFocus: true,
      showPanIcon: true,
      panIconStyle: {
        height: "16px",
        top: "calc(50% - 8px)",
        right: "8px",
      },
      fields: {
        pan: {
          container: document.querySelector("#pan"),
        },
        expiry: {
          container: document.querySelector("#expiry"),
        },
        cvc: {
          container: document.querySelector("#cvc"),
        },
      },
      styles: {
        base: {
          padding: "0px 16px",
          color: "black",
          fontSize: "18px",
          fontFamily: 'monospace',
        },
        invalid: {
          color: "red",
        },
        placeholder: {
          base: {
            color: "gray",
          },
          focus: {
            color: "transparent",
          },
        },
      },
    });

    // Action après l'initialisation
    webSdkFormWithoutBindings.init().then(() => {
      document
        .querySelector(".payment-form-loader")
        .classList.remove("payment-form-loader--active");
      })
      .catch((e) => {
        // Affichage de l'erreur lors de l'initialisation webSDK
        const errorEl = document.querySelector('#error_1');
        errorEl.innerHTML = e.message;
        errorEl.classList.remove('visually-hidden');
      }
      .finally(() => {
        // Validation et remplacement automatique des caractères non autorisés
        mandatoryFieldsWithBinding.forEach(item => {
          const field = document.querySelector(item.id)
          field.closest(".additional-field").style.display = '';
          field.addEventListener('input', () => {
              let inputValue = field.querySelector('input')
              inputValue.value = item.replace ? inputValue.value.replace(item.replace,'') : inputValue.value;
              if (item.id.includes("#cardholder")) {
                  inputValue.value = inputValue.value.toUpperCase()
              }
              if (item.template) {
                  // Classe CSS ".additional-field-invalid" pour afficher les champs non valides
                  if (item.template.test(inputValue.value)) {
                      field.classList.remove("additional-field-invalid")
                  } else {
                      field.classList.add("additional-field-invalid")
                  }
              }
          })
        })
      })
  }

  // Gestionnaire "Payer"
  document.querySelector("#pay").addEventListener("click", () => {
    const payButton = document.querySelector("#pay");

    // Désactivons le bouton "Payer" pour éviter les doubles paiements
    payButton.disabled = true;

    // Affichons le chargeur à l'utilisateur
    const spinnerEl = document.querySelector("#pay-spinner");
    spinnerEl.classList.remove("visually-hidden");

    // Masquons le conteneur d'erreur
    const errorEl = document.querySelector("#error");
    errorEl.classList.add("visually-hidden");
    // Validation des champs supplémentaires Visa Mandatory
    if (document.querySelectorAll('.additional-field-invalid').length) {
      errorEl.innerHTML = "Form is not valid";
      errorEl.classList.remove('visually-hidden');
      spinnerEl.classList.add('visually-hidden');
      return
    }

    // Commençons le processus de paiement
    webSdkFormWithoutBindings
      .doPayment({
        // Paramètres supplémentaires
        email: document.querySelector('#email input').value,
        phone: document.querySelector('#mobile input').value,
        cardholderName: document.querySelector('#cardholder input').value,
        jsonParams: { size: "L" },
      })
      .then((result) => {
        console.log("result", result);
      })
      .catch((e) => {
        // Exécuté en cas d'erreur
        errorEl.innerHTML = e.message;
        errorEl.classList.remove("visually-hidden");
      })
      .finally(() => {
        // S'exécute dans tous les cas, par exemple, nous rendons le bouton "Payer" à nouveau actif.
        payButton.disabled = false;
        spinnerEl.classList.add("visually-hidden");
      });
  });

  // Gestionnaire "Détruire"
  document
    .querySelector("#destroyFormWithoutCredentials")
    .addEventListener("click", function () {
      // Supprimons le bouton "Détruire" et affichons le bouton "Initialiser" pour la démonstration
      this.style.display = "none";
      document.querySelector("#reinitFormWithoutCredentials").style.display =
        "";
      // Détruisons le formulaire de paiement Web SDK
      webSdkFormWithoutBindings.destroy();
    });

  // Gestionnaire "Initialiser le formulaire"
  document
    .querySelector("#reinitFormWithoutCredentials")
    .addEventListener("click", function () {
      // Supprimons le bouton "Initialiser" et affichons le bouton "Détruire" pour la démonstration
      this.style.display = "none";
      document.querySelector("#destroyFormWithoutCredentials").style.display =
        "";
      // Initialisation du formulaire de paiement
      initPaymentForm();
    });
});
</script>

Paiement avec une carte sauvegardée (liaison)

Étape 1. Exécuter la méthode d'initialisation

Après avoir défini les paramètres du Web SDK, il est nécessaire d'appeler init(). Cette fonction retourne un callback, où vous pouvez, par exemple, masquer le chargeur ou faire autre chose. init() retourne une Promise.

Par exemple :

// Initialisation
webSdkFormWithBindings
  .init()
  .then(({ orderSession }) => {
    // L'objet `orderSession` contient toutes les informations sur la commande, y compris les informations sur les identifiants sauvegardés (sur la liaison).
    console.info("orderSession", orderSession);

    // Afficher l'élément de sélection de la carte sauvegardée
    document.querySelector("#select-binding-container").style.display =
      orderSession.bindings.length ? "" : "none";

    // Remplir la sélection avec les identifiants sauvegardés
    orderSession.bindings.forEach((binding) => {
      document
        .querySelector("#select-binding")
        .options.add(new Option(binding.pan, binding.id));
    });

    // Traitement de la sélection des identifiants sauvegardés ou d'une nouvelle carte
    document
      .querySelector("#select-binding")
      .addEventListener("change", function () {
        const bindingId = this.value;
        if (bindingId !== "new_card") {
          webSdkFormWithBindings.selectBinding(bindingId);

          // Masquer la case à cocher "Sauvegarder la carte"
          document.querySelector("#save-card-container").style.display = "none";
        } else {
          // La sélection de liaison avec null signifie le passage à une nouvelle carte
          webSdkFormWithBindings.selectBinding(null);

          // Afficher la case à cocher "Sauvegarder la carte"
          document.querySelector("#save-card-container").style.display = "";
        }
      });

    // Quand le formulaire est prêt, nous pouvons masquer le chargeur
    document.querySelector("#pay-form-loader").classList.add("visually-hidden");
  })
  .catch((error) => {
    // Des erreurs se sont produites lors de l'initialisation du script. L'exécution ultérieure est impossible.
    // Promise retourne un message d'erreur que nous pouvons afficher sur la page :
    const errorEl = document.querySelector('#error_1');
    errorEl.innerHTML = e.message;
    errorEl.classList.remove('visually-hidden');
  });

Étape 2. Traitement du clic sur le bouton de paiement. Exécuter la méthode de paiement

Pour effectuer le paiement, appelez la fonction doPayment(). Il n'est pas nécessaire d'envoyer les données de la carte, le Web SDK le fera. doPayment() retourne une Promise.

La méthode accepte les paramètres suivants :

phone String optional
Numéro de téléphone du client

saveCard boolean optional
Option de sauvegarde de carte. Par exemple, document.querySelector('#save-card').checked

email String optional
Email du client

cardholderName String optional
Nom du porteur de la carte.

jsonParams Object optional
Champs supplémentaires. Par exemple, vous pouvez envoyer des informations supplémentaires sur la commande ou toute autre information utile pour vous. Par exemple, jsonParams: { "t-shirt-color": "noir", "size": "M" }

Application des cartes sauvegardées

Pour payer avec des identifiants sauvegardés, vous devez passer le bindingId sélectionné dans le formulaire avant d'appeler doPayment :
webSdkFormWithBindings.selectBinding('bindingId');

Si vous changez d'avis et voulez payer avec une nouvelle carte, n'oubliez pas de supprimer le bindingId du formulaire :
webSdkFormWithBindings.selectBinding(null);

Exemple d'appel :

webSdkFormWithBindings
  .doPayment({
    // Paramètres supplémentaires
    email: "foo@bar.com",
    phone: "4420123456789",
    saveCard: document.querySelector("#save-card").checked,
    cardholderName: "JOHN DOE",
    jsonParams: { foo: "bar" },
  })
  .then((result) => {
    console.log("result", result);
  })
  .catch((e) => {
    // Traitement des erreurs. À titre d'exemple, nous afficherons un bloc avec l'erreur
    errorEl.innerHTML = e.message;
    errorEl.classList.remove("visually-hidden");
  })
  .finally(() => {
    // Exécuter dans tous les cas. Par exemple, rendre le bouton "Payer" à nouveau actif.
    payButton.disabled = false;
    spinnerEl.classList.add("visually-hidden");
  });

Démonstration avec carte sauvegardée

Pour le fonctionnement de Web SDK Payment nécessite un Order ID (identifiant de commande enregistré dans la passerelle de paiement).
Pour les objectifs de travail - enregistrez la commande via l'API.

Ce formulaire est utilisé uniquement à des fins de démonstration - utilisez la valeur Order ID = xxxxx-xxxxx-xxxxx-xxxxx

Tout le code de démonstration

<div class="container_demo">
    <div class="about">
        <form name="formRunTest">
            <label for="mdOrder"> Identifiant de commande (mdOrder) <br/>
              <span class="label__desc">(Fourni uniquement à des fins de démonstration. L'identifiant de commande doit provenir du backend.)</span>
            </label>
            <div class="run-test">
                <input id="mdOrder" type="text" placeholder="Insérez le mdOrder enregistré dans Sandbox"/>
                <button class="btn-mini" id="load" type="submit">Charger</button>
            </div>
        </form>
    </div>
    <div class="payment-form">

        <div class="payment-form-loader payment-form-loader--active">
 Web SDK Payment nécessite un mdOrder (commande préalablement enregistrée dans la passerelle).<br/>
 Vous pouvez enregistrer une commande via l'interface utilisateur ou via l'API. <br/><br/>
 Ou essayez d'utiliser <code>xxxxx-xxxxx-xxxxx-xxxxx</code> si vous souhaitez uniquement tester le formulaire de paiement.
        </div>

        <div id="pay-form-loader" class="spinner-container visually-hidden">
            <div class="spinner-border" role="status"></div>
        </div>
        <div class="card-body">
            <div class="col-12" id="select-binding-container" style="display: none">
              <select class="form-select" id="select-binding" aria-label="Default select example">
                <option selected value="new_card">Paiement avec nouvelle carte</option>
              </select>
            </div>
            <div class="col-12">
                <label for="pan" class="form-label">Numéro de carte</label>
                <div id="pan" class="form-control"></div>
            </div>
            <div class="col-6 col-expiry">
                <label for="expiry" class="form-label">Date d'expiration</label>
                <div id="expiry" class="form-control"></div>
            </div>
            <div class="col-6 col-cvc">
                <label for="cvc" class="form-label">CVC / CVV</label>
                <div id="cvc" class="form-control"></div>
            </div>
            <label class="col-12" id="save-card-container">
                <input class="form-check-input" type="checkbox" value="" id="save-card" />
                Sauvegarder la carte
            </label>
            <!--Champs supplémentaires Visa Mandatory -->
            <div class="col-12 additional-field" style="display:none;">
              <label for="" class="form-label">Titulaire de la carte</label>
              <div id="cardholder" class="additional-field-container">
                  <input type="text" class="additional-field-input" placeholder="NAME SURNAME"value="JOHN DOE">
              </div>
            </div>
            <div class="col-12 additional-field"  style="display:none;">
                <label for="" class="form-label">Téléphone</label>
                <div id="mobile" class="additional-field-container">
                    <input type="tel" class="additional-field-input" placeholder="+4915112345" value="+4915112345678">
                </div>
            </div>
            <div class="col-12 additional-field" style="display:none;">
                <label for="" class="form-label">Courrier électronique</label>
                <div id="email" class="additional-field-container">
                    <input type="text" class="additional-field-input" placeholder="address@mail" value="address@mail.com">
                </div>
            </div>
        </div>
        <button class="btn btn-primary btn-lg" type="submit" id="pay">
            <span
            class="spinner-border spinner-border-sm me-2 visually-hidden"
            role="status"
            aria-hidden="true"
            id="pay-spinner">
            </span>
            <span>Payer</span>
        </button>
        <!-- Ces boutons ne sont nécessaires que pour démontrer le fonctionnement de la méthode destroy -->
        <button class="btn btn-secondary" type="button" id="destroyFormWithoutCredentials">
            <span>Détruire</span>
        </button>
        <button class="btn btn-secondary" type="button" id="reinitFormWithoutCredentials" style="display: none;">
            <span>Initialiser</span>
        </button>
        <div class="error my-2 visually-hidden" id="error"></div>
    </div>
</div>

<script>
document.addEventListener("DOMContentLoaded", () => {
  // Fonction pour initialiser le formulaire de paiement pour sa réutilisation après destruction
  function initPaymentForm() {
    const mrOrderInput = document.getElementById("mdOrder");
    mrOrderInput.classList.remove("invalid");
    if (!/(\w+-){3,10}\w+/g.test(mrOrderInput.value)) {
      mrOrderInput.classList.add("invalid");
      return;
    }
    // Suppression du placeholder
    document
      .querySelector(".payment-form-loader")
      .classList.remove("payment-form-loader--active");
    // Ajout du chargeur de formulaires de paiement
    document
      .querySelector("#pay-form-loader")
      .classList.remove("visually-hidden");

    // Initialisation Web SDK. Nécessite un mdOrder obligatoire (identifiant de commande).
    initPayment(mrOrderInput.value);
  }

  // Initialisation du gestionnaire pour les données de test
  function handleSubmit(e) {
    e.preventDefault();
    // Initialiser le formulaire de paiement
    initPaymentForm();
  }

  // Enregistrement de l'événement pour l'exemple de saisie
  document.formRunTest.addEventListener("submit", handleSubmit);

  let webSdkFormWithBindings;
  // Tableau d'objets pour les champs supplémentaires, qui contiennent l'id du champ, son modèle de validation et les caractères autorisés pour la saisie
  const mandatoryFieldsWithoutBinding = [
    {
        id: '#cardholder',
        template: /^[a-zA-Z '`.\-]{4,24}$/,
        replace: /[^a-zA-Z ' \-`.]/g,
    },
    {
        id: '#mobile',
        template: /^\+?[1-9][0-9]{7,14}$/,
        replace: /[^0-9\+]/g,
    },
    {
        id: '#email',
        template: /^[a-zA-Z0-9._-]{1,64}@([a-zA-Z0-9.-]{2,255})\.[a-zA-Z]{2,255}$/,
        replace: /[^a-zA-Z0-9@._-]/g,
    }
  ]

  function initPayment(mdOrder) {
    webSdkFormWithBindings = new window.PaymentForm({
      // Numéro de commande (l'enregistrement de la commande se fait avant l'initialisation du formulaire)
      mdOrder: mdOrder,
      // Traitement de la validation du formulaire
      onFormValidate: (isValid) => {
        // Par exemple, vous pouvez désactiver les boutons "Payer" et "Obtenir le jeton" si le formulaire n'est pas valide, par exemple :
        // const payButton = document.querySelector('#pay');
        // payButton.disabled = !isValid;
      },
      // Contexte pour les appels API
      apiContext: "/payment",
      // La langue est utilisée pour la localisation des erreurs et des noms pour les placeholders.
      // La langue doit être prise en charge dans les paramètres du marchand
      language: "en",
      // Nom de classe pour les éléments conteneurs contenant l'iframe
      containerClassName: "field-container",
      // Commutation automatique du focus lors du remplissage des champs
      autoFocus: true,
      // Afficher l'icône du système de paiement
      showPanIcon: true,
      // Styles supplémentaires pour l'icône du système de paiement
      panIconStyle: {
        height: "16px",
        top: "calc(50% - 8px)",
        right: "8px",
      },
      // Paramètres de champ
      fields: {
        // Élément-conteneur dans lequel sera placé l'iframe avec le champ
        pan: {
          container: document.querySelector("#pan"),
        },
        // Date d'expiration de la carte
        expiry: {
          container: document.querySelector("#expiry"),
        },
        // Code CVC/CVV
        cvc: {
          container: document.querySelector("#cvc"),
        },
      },
      // Styles supplémentaires pour personnaliser l'apparence des champs de saisie dans les iframes
      styles: {
        base: {
          padding: "0px 16px",
          color: "black",
          fontSize: "18px",
          fontFamily: 'monospace',
        },
        disabled: {
          backgroundColor: "#e9ecef",
        },
        invalid: {
          color: "red",
        },
        placeholder: {
          base: {
            color: "gray",
          },
          focus: {
            color: "transparent",
          },
        },
      },
    });

    // Action après initialisation
    webSdkFormWithBindings
      .init()
      .then(({ orderSession }) => {
        // L'objet `orderSession` contient toutes les informations sur la commande, y compris les informations sur les identifiants sauvegardés (sur la liaison).
        console.info("orderSession", orderSession);

        // Afficher la liaison sélectionnée
        document.querySelector("#select-binding-container").style.display =
          orderSession.bindings.length ? "" : "none";

        // Remplir la sélection avec les identifiants sauvegardés
        orderSession.bindings.forEach((binding) => {
          document
            .querySelector("#select-binding")
            .options.add(new Option(binding.pan, binding.id));
        });

        // Traitement de la sélection des identifiants sauvegardés ou d'une nouvelle carte
        document
          .querySelector("#select-binding")
          .addEventListener("change", function () {
            const bindingId = this.value;
            if (bindingId !== "new_card") {
              // Définir l'identifiant de liaison
              webSdkFormWithBindings.selectBinding(bindingId);

              // Hide the 'Save card' checkbox
              document.querySelector("#save-card-container").style.display =
                "none";
            } else {
              // Sélection de liaison avec null signifie passer à une nouvelle carte
              webSdkFormWithBindings.selectBinding(null);

              // Afficher la case à cocher "Sauvegarder la carte"
              document.querySelector("#save-card-container").style.display = "";
            }
          });

        // Quand le formulaire est prêt, nous pouvons masquer le chargeur
        document
          .querySelector("#pay-form-loader")
          .classList.add("visually-hidden");

        // Supprimer l'événement pour l'exemple de saisie
        document.formRunTest.removeEventListener("submit", handleSubmit);
      })
      .catch((error) => {
        // Exécuter en cas d'erreur
        const errorEl = document.querySelector("#error");
        errorEl.innerHTML = e.message;
        errorEl.classList.remove("visually-hidden");
      })
      .finally(() => {
        // Validation et remplacement automatique des caractères non autorisés
        mandatoryFieldsWithBinding.forEach(item => {
          const field = document.querySelector(item.id)
          field.closest(".additional-field").style.display = '';
          field.addEventListener('input', () => {
              let inputValue = field.querySelector('input')
              inputValue.value = item.replace ? inputValue.value.replace(item.replace,'') : inputValue.value;
              if (item.id.includes("#cardholder")) {
                  inputValue.value = inputValue.value.toUpperCase()
              }
              if (item.template) {
                  // Classe CSS ".additional-field-invalid" pour afficher les champs non valides
                  if (item.template.test(inputValue.value)) {
                      field.classList.remove("additional-field-invalid")
                  } else {
                      field.classList.add("additional-field-invalid")
                  }
              }
          })
        })
      });

  }

  // Gestionnaire de paiement
  document.querySelector("#pay").addEventListener("click", () => {
    // Rendre le bouton "Payer" inactif pour éviter les doubles paiements
    const payButton = document.querySelector("#pay");
    payButton.disabled = true;

    // Afficher le chargeur pour l'utilisateur
    const spinnerEl = document.querySelector("#pay-spinner");
    spinnerEl.classList.remove("visually-hidden");

    // Masquer le conteneur d'erreurs
    const errorEl = document.querySelector("#error");
    errorEl.classList.add("visually-hidden");
    // Validation des champs supplémentaires Visa Mandatory
    if (document.querySelectorAll('.additional-field-invalid').length) {
      errorEl.innerHTML = "Form is not valid";
      errorEl.classList.remove('visually-hidden');
      spinnerEl.classList.add('visually-hidden');
      return
    }

    // Commencer le paiement
    webSdkFormWithBindings
      .doPayment({
        // Paramètres supplémentaires
        email: document.querySelector('#email input').value,
        phone: document.querySelector('#mobile input').value,
        cardholderName: document.querySelector('#cardholder input').value,
        saveCard: document.querySelector("#save-card").checked,
        jsonParams: { foo: "bar" },
      })
      .then((result) => {
        // Ici, on peut faire quelque chose avec le résultat du paiement
        console.log("result", result);
      })
      .catch((e) => {
        // Exécuter en cas d'erreur
        errorEl.innerHTML = e.message;
        errorEl.classList.remove("visually-hidden");
      })
      .finally(() => {
        // Exécuter dans tous les cas. Par exemple, réactiver le bouton « Payer ».
        payButton.disabled = false;
        spinnerEl.classList.add("visually-hidden");
      });
  });

  // gestionnaire Destroy
  document
    .querySelector("#destroyFormWithCredentials")
    .addEventListener("click", function () {
      // Supprimer le bouton Destroy et afficher le bouton de réinitialisation pour la démonstration
      this.style.display = "none";
      document.querySelector("#reinitFormWithCredentials").style.display = "";
      // Exécuter la méthode destroy dans le SDK de formulaire web
      webSdkFormWithBindings.destroy();
    });

  // Déclencher le gestionnaire du formulaire de paiement
  document
    .querySelector("#reinitFormWithCredentials")
    .addEventListener("click", function () {
      // Supprimer le bouton Reinit et afficher le bouton Destroy pour la démonstration
      this.style.display = "none";
      document.querySelector("#destroyFormWithCredentials").style.display = "";
      // Initialisation du formulaire de paiement
      initPaymentForm();
    });
});
</script>

Traitement des données renvoyées par les méthodes init( ) et doPayment( )

Méthode init( )

La méthode renvoie une Promise qui, en cas d'exécution réussie, renvoie un objet avec des informations sur la commande enregistrée. Pour des raisons de sécurité, cet objet ne contient pas de données de carte et autres informations confidentielles.

La méthode renvoie les paramètres suivants :

mdOrder string optional
Numéro de commande transmis lors de l'initialisation

Objet avec des informations sur la commande enregistrée

La présence de champs supplémentaires ou l'absence de certains champs de la liste ci-dessus est possible.

Exemple

{
  "mdOrder": "5541f44c-d7ec-7a6c-997d-1d4d0007bc7d",
  "orderSession": {
      "amount": "100000",
      "currencyAlphaCode": "BYN",
      "currencyNumericCode": "933",
      "sessionTimeOverAt": 1740385187287,
      "orderNumber": "27000",
      "description": "",
      "cvcNotRequired": false,
      "bindingEnabled": false,
      "bindingDeactivationEnabled": false,
      "merchantOptions": [
          "MASTERCARD_TDS",
          "MASTERCARD",
          "VISA",
          "VISA_TDS",
          "CARD"
      ],
      "customerDetails": {},
      "merchantInfo": {
          "merchantUrl": "http://google.com",
          "merchantFullName": "Coffee to Go",
          "merchantLogin": "CoffeToGo",
          "captchaMode": "NONE",
          "loadedResources": {
              "logo": true,
              "footer": false
          },
          "custom": false
      },
      "bindings": [
            {
                "cardholderName": "CARDHOLDER NAME",
                "createdAt": 1712321609666,
                "id": "83ffea5d-061f-7eca-912a-02ff0007bc7d",
                "pan": "4111 11** **** 1111",
                "expiry": "12/24",
                "cardInfo": {
                    "name": "TEST BANK-A",
                    "nameEn": "TEST BANK-A",
                    "backgroundColor": "#fbf0ff",
                    "backgroundGradient": [
                        "#fafafa",
                        "#f3f0ff"
                    ],
                    "supportedInvertTheme": false,
                    "backgroundLightness": true,
                    "country": "hu",
                    "defaultLanguage": "en",
                    "textColor": "#040e5d",
                    "url": null,
                    "logo": "logo/main/293c39ad-0bcb-4cbb-803e-65c435877b5a/1.svg",
                    "logoInvert": "logo/invert/293c39ad-0bcb-4cbb-803e-65c435877b5a/1.svg",
                    "logoMini": "logo/mini/293c39ad-0bcb-4cbb-803e-65c435877b5a/1.svg",
                    "design": null,
                    "paymentSystem": "visa",
                    "cobrand": null,
                    "productCategory": null,
                    "productCode": null,
                    "mnemonic": "TEST BANK-A",
                    "params": null
                }
            }
      ]
  }
}

Exécution non réussie

En cas d'exécution non réussie, Promise renvoie un message d'erreur que nous pouvons afficher sur la page. Exemple de message : Error: Forme invalide.

Des exemples de code de traitement des données renvoyées par la méthode d'initialisation init() sont fournis dans la section Étape 1. Exécuter la méthode d'initialisation pour le paiement sans carte sauvegardée et avec carte sauvegardée.

Méthode doPayment( )

La méthode renvoie Promise, qui lors d'une exécution réussie renvoie un objet avec des informations sur le paiement effectué.

La méthode renvoie les paramètres suivants :

redirectUrl string optional
Adresse de redirection après effectuation du paiement

Objet avec des informations sur le paiement effectué

Présence possible de champs supplémentaires, ou absence de certains champs de la liste ci-dessus.

Exemple

{
    "redirectUrl": "https://bankhost.com/payment/merchants/ecom/finish.html?orderId=568b2db6-2acc-79e7-9ed8-746a00cd6608&lang=en",
    "finishedPaymentInfo": {
        "paymentSystem": "MASTERCARD",
        "merchantShortName": "CoffeToGo",
        "merchantLogin": "CoffeToGo",
        "merchantFullName": "Coffee to Go",
        "approvalCode": "123456",
        "orderNumber": "4003",
        "formattedTotalAmount": "15.00",
        "backUrl": "https://www.coffeetogo.com/congratulation?orderId=568b2db6-2acc-79e7-9ed8-746a00cd6608&lang=en",
        "failUrl": "https://www.coffeetogo.com/someproblem?orderId=568b2db6-2acc-79e7-9ed8-746a00cd6608&lang=en",
        "terminalId": "12345678",
        "orderDescription": "Order 123",
        "displayErrorMessage": "",
        "loadedResources": {
            "footer": false,
            "logo": false
        },
        "currencyAlphaCode": "EUR",
        "orderFeatures": [
            "ACS_IN_IFRAME",
            "BINDING_NOT_NEEDED"
        ],
        "isWebView": false,
        "actionCodeDetailedDescription": "Request processed successfully",
        "transDate": "29.11.2024 15:19:30",
        "currency": "978",
        "actionCode": 0,
        "expiry": "12/2024",
        "formattedAmount": "15.00",
        "actionCodeDescription": "",
        "formattedFeeAmount": "0.00",
        "email": "address@mail.com",
        "amount": "1500",
        "merchantCode": "12345678",
        "ip": "x.x.x.x",
        "panMasked": "555555**5599",
        "successUrl": "https://www.coffeetogo.com/congratulation?orderId=568b2db6-2acc-79e7-9ed8-746a00cd6608&lang=en",
        "paymentWay": "CARD",
        "processingErrorType": {
            "value": "NO_ERROR",
            "messageCode": "payment.errors.no_error",
            "apiErrorCodeMessage": "payment.errors.no_error.code"
        },
        "panMasked4digits": "**** **** **** 5599",
        "amountsInfo": {
            "currencyDto": {
                "alphabeticCode": "EUR",
                "numericCode": "978",
                "minorUnit": 2
            },
            "depositedAmount": {
                "value": 1500,
                "formattedValue": "15.00"
            },
            "totalAmount": {
                "value": 1500,
                "formattedValue": "15.00"
            },
            "refundedAmount": {
                "value": 0,
                "formattedValue": "0.00"
            },
            "approvedAmount": {
                "value": 1500,
                "formattedValue": "15.00"
            },
            "feeAmount": {
                "value": 0,
                "formattedValue": "0.00"
            },
            "paymentAmount": {
                "value": 1500,
                "formattedValue": "15.00"
            },
            "amount": {
                "value": 1500,
                "formattedValue": "15.00"
            },
            "depositedTotalAmount": {
                "value": 1500,
                "formattedValue": "15.00"
            }
        },
        "errorTypeName": "SUCCESS",
        "feeAmount": "0",
        "totalAmount": "1500",
        "orderParams": {
            "phone": "+4915112345678",
            "foo": "bar",
            "paymentMethod": "multiframe-sdk"
        },
        "orderExpired": false,
        "refNum": "111111111111",
        "finishPageLogin": "ecom",
        "sessionExpired": false,
        "cardholderName": "JOHN DOE",
        "paymentDate": "29.11.2024 15:19:49",
        "merchantUrl": "https://www.coffeetogo.com/",
        "status": "DEPOSITED"
    }
}

Exécution non réussie

En cas d'exécution non réussie, la Promise retourne un message d'erreur que nous pouvons afficher sur la page. Exemple de message : Error: Operation declined. Please check the data and available balance of the account.

Les exemples de code de traitement des données retournées par la méthode doPayment() sont donnés dans la section Étape 2. Traitement du clic sur le bouton de paiement. Exécuter la méthode de paiement pour le paiement sans carte enregistrée et avec carte enregistrée

Redirection automatique après le paiement

Après le paiement, une redirection automatique se produit depuis la page avec Web SDK. Pour traiter l'objet retourné par la méthode doPayment() directement sur la page avec Web SDK, il faut désactiver la redirection automatique après le paiement. Pour cela, une autorisation spéciale est requise dans le système ‒ dans la passerelle de paiement pour ce marchand, la permission Support Acs IFrame activé doit être activée. Pour obtenir l'autorisation, contactez le service de support technique de la banque. Aussi, lors de l'initialisation du Web SDK, l'objet transmis doit contenir la propriété shouldHandleResultManually: true.

Par exemple :

webSdkForm = new window.PaymentForm({
      ...
      shouldHandleResultManually: true,
      ...
  });

Web SDK dans React SPA

Lors de l'utilisation du Web SDK dans une single page application (SPA) sur React, il est nécessaire d'initialiser le Web SDK en exécutant la méthode webSdkPaymentForm.init() à chaque rendu initial de la page avec le formulaire Web SDK dans la SPA.

Lors de l'événement de réinitialisation de la page avec le formulaire Web SDK (c'est-à-dire lors de la transition vers une autre page), il est nécessaire d'exécuter la méthode webSdkPaymentForm.destroy(). Ceci est important, car il ne doit rester qu'un seul gestionnaire de formulaire webSDK (multiframe-commutator) sur la page.

Lors du retour sur la page avec le formulaire Web SDK, il est nécessaire de procéder à nouveau à l'initialisation à l'aide de la méthode webSdkPaymentForm.init().

Veuillez noter que l'utilisation de cette bibliothèque nécessite la conformité à la norme PCI DSS, car elle traite les données de carte. Plus d'informations sur PCI DSS ici.

Exemple de composant React

import { useEffect, useRef } from "react";

function addScript(src) {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");

    script.setAttribute("src", src);
    script.addEventListener("load", resolve);
    script.addEventListener("error", reject);

    document.body.appendChild(script);
  });
}

function App() {
  const panRef = useRef(null);
  const expiryRef = useRef(null);
  const cvcRef = useRef(null);
  const selectBindingRef = useRef(null);
  const saveCardContainerRef = useRef(null);
  const payButtonRef = useRef(null);
  let webSdkPaymentForm = null;

  useEffect(() => {
    const initPaymentForm = async () => {
      await addScript(
        "https://dev.bpcbt.com/payment/modules/multiframe/main.js",
      );

      webSdkPaymentForm = new window.PaymentForm({
        mdOrder: mdOrder,
        containerClassName: "field-container",
        onFormValidate: (isValid) => {
          // Gestion de la validation du formulaire
        },
        apiContext: "/payment",
        language: "en",
        autoFocus: true,
        showPanIcon: true,
        panIconStyle: {
          height: "16px",
          top: "calc(50% - 8px)",
          right: "8px",
        },
        fields: {
          pan: {
            container: panRef.current,
            onFocus: (containerElement) => {
              // Gestion du focus
            },
            onBlur: (containerElement) => {
              // Gestion de la perte de focus
            },
            onValidate: (isValid, containerElement) => {
              // Gestion de la validation
            },
          },
          expiry: {
            container: expiryRef.current,
            // Configuration du champ date d'expiration
          },
          cvc: {
            container: cvcRef.current,
            // Configuration du champ CVC/CVV
          },
        },
        styles: {
          base: {
            padding: "0px 16px",  
            color: "black",
            fontSize: "18px",
            fontFamily: 'monospace',
          },
          focus: {
            color: "blue",
          },
          disabled: {
            color: "gray",
          },
          valid: {
            color: "green",
          },
          invalid: {
            color: "red",
          },
          placeholder: {
            base: {
              color: "gray",
            },
            focus: {
              color: "transparent",
            },
          },
        },
      });

      webSdkPaymentForm
        .init()
        .then(({ orderSession }) => {
          console.info("orderSession", orderSession);

          if (orderSession.bindings.length) {
            selectBindingRef.current.style.display = "";
          } else {
            selectBindingRef.current.style.display = "none";
          }

          if (orderSession.bindingEnabled) {
            saveCardContainerRef.current.style.display = "";
          } else {
            saveCardContainerRef.current.style.display = "none";
          }

          orderSession.bindings.forEach((binding) => {
            const option = new Option(binding.pan, binding.id);
            selectBindingRef.current.options.add(option);
          });
        })
        .catch(() => {
          // Gestion de l'erreur d'initialisation
        });
    };

    initPaymentForm();

    return () => {
      if (webSdkPaymentForm) {
        webSdkPaymentForm.destroy();
      }
    };
  }, []);

  const handlePayment = () => {
    payButtonRef.current.disabled = true;

    webSdkPaymentForm
      .doPayment({})
      .then((result) => {
        // Gestion du paiement réussi
      })
      .catch((e) => {
        alert("Error");
      })
      .finally(() => {
        payButtonRef.current.disabled = false;
      });
  };

  const handleSelectBinding = () => {
    const bindingId = selectBindingRef.current.value;
    if (bindingId !== "new_card") {
      webSdkPaymentForm.selectBinding(bindingId);
      saveCardContainerRef.current.style.display = "none";
    } else {
      webSdkPaymentForm.selectBinding(null);
      saveCardContainerRef.current.style.display = "";
    }
  };

  return (
    <div className="container">
      <div className="websdk-form">
        <div className="card-body">
          <div
            className="col-12"
            id="select-binding-container"
            onChange={handleSelectBinding}
          >
            <select
              className="form-select"
              id="select-binding"
              ref={selectBindingRef}
              aria-label="Default select example"
            >
              <option value="new_card">Payer avec une nouvelle carte</option>
            </select>
          </div>
          <div className="col-12 input-form">
            <label htmlFor="pan" className="form-label">
              Numéro de carte
            </label>
            <div id="pan" className="form-control" ref={panRef}></div>
          </div>
          <div className="col-6 col-expiry input-form">
            <label htmlFor="expiry" className="form-label">
              Expiration
            </label>
            <div id="expiry" className="form-control" ref={expiryRef}></div>
          </div>
          <div className="col-6 col-cvc">
            <label htmlFor="cvc" className="form-label">
              CVC / CVV
            </label>
            <div id="cvc" className="form-control" ref={cvcRef}></div>
          </div>
          <label className="col-12" id="save-card-container">
            <input
              className="form-check-input me-1"
              ref={saveCardContainerRef}
              type="checkbox"
              value=""
              id="save-card"
            />
            Sauvegarder la carte
          </label>
        </div>
        <div className="pay-control">
          <button
            className="btn btn-primary btn-lg"
            type="submit"
            id="pay"
            ref={payButtonRef}
            onClick={handlePayment}
          >
            Payer
          </button>
        </div>
        <div
          className="error my-2 text-center text-danger visually-hidden"
          id="error"
        ></div>
      </div>
    </div>
  );
}

export default App;
Catégories:
eCommerce SDK
Catégories
Résultats de recherche