Modèle de pilote de paiement.
Alors vous voulez créer un pilote de paiement pour Invoice Ninja, mais vous ne savez pas par où commencer? La première étape serait de nous contacter directement sur Slack https://invoiceninja.slack.com et d'avoir une discussion en temps réel avec nous afin que nous puissions vous aider à démarrer rapidement et à construire votre pilote de la manière la plus efficace possible. Nous contacter au préalable nous permettra également de nous assurer que votre code peut être fusionné avec le dépôt officiel, car nous en assurerons la maintenance à l'avenir.
Prêt? Allons-y!
Vous devriez mettre à jour votre code pour être à jour avec la branche v5-develop.
Vous voudrez ensuite créer votre propre branche pour votre pilote, c'est-à-dire.
git branch my_payment_driver
Créons un fichier de migration qui insérera un enregistrement identifiant la passerelle.
php artisan make:migration my_new_gateway
Ouvrons ce fichier et dans la méthode up() créons notre nouvel enregistrement de passerelle
Init une nouvelle instance de gateway
$gateway = new Gateway;
$gateway->name = 'Passerelle Élégante';
$gateway->key = Str::lower(Str::random(32));
$gateway->provider = ‘PasserelleÉlégante’;
$gateway->is_offsite = true;
$gateway->fields = new \\stdClass;
$gateway->visible = true;
$gateway->site_url = ‘https://stripe.com’;
$gateway->default_gateway_type_id = 1;
$gateway->save();
const CARTE_CREDIT = 1;
const TRANSFERT_BANCAIRE = 2;
const PAYPAL = 3;
const CRYPTO = 4;
const PERSONNALISE = 5;
const ALIPAY = 6;
const SOFORT = 7;
const APPLE_PAY = 8;
const SEPA = 9;
const CREDIT = 10;
Deux méthodes doivent être ajoutées à :
getHelp()
renvoie un lien vers la page d'aide des passerelles. Nous affichons un lien dans l'interface utilisateur pour que l'utilisateur puisse ouvrir une page Web directe vers la passerelle.getMethods()
renvoie un tableau des types de passerelle pris en charge (c'est-à-dire les méthodes de paiement), si la passerelle prend en charge les remboursements et la facturation par jeton, ainsi que les métadonnées du webhook. La structure du tableau ressemble à ceci :[
[GatewayType::CREDIT_CARD => ['remboursement' => true, 'facturation_par_jeton' => true]],
[GatewayType::BANK_TRANSFER => ['remboursement' => true, 'facturation_par_jeton' => true, 'webhooks' => ['source.chargeable']]]
];
Le tableau est stocké dans un bloc case/switch, qui change en fonction de la propriété gateway->id.
Tous les pilotes de paiement doivent étendre la classe BaseDriver qui étend elle-même la classe abstraite AbstractPaymentDriver qui impose les méthodes requises suivantes. Nous avons ébauché un exemple de classe de pilote de paiement et des fichiers de vue qui peuvent être téléchargés ici
abstract public function autoriserVoir(array $data);
fonction publique abstraite authorizeResponse(Requête $request);
Note : Le texte ne contient pas de balises HTML, de liens ou d'images en format Markdown à conserver ou traduire.
fonction publique abstraite processPaymentView(array $data);
fonction abstraite publique processPaymentResponse (Requête $request);
fonction publique abstraite refund(Paiement $paiement, $montant_remboursement, $retour_reponse_client = false);
fonction publique abstraite tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash);
fonction publique abstraite setPaymentMethod($payment_method_id);
Pour comprendre les dispositions de l'interface utilisateur, il est intéressant d'examiner les dispositions des autres pilotes de paiement dans resources/views/portal/ninja2020/gateways.
Toutes les mises en page sont basées sur la suivante:
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => ctrans('texts.credit_card')])
ClientGatewayToken
suivi du retour de l'utilisateur à la route suivantereturn redirect()->route('client.moyens_de_paiement.index');
Note : Since it's a code block, only the comment has been translated.
Payment
suivi du retour de l'utilisateur à la route de paiement ici:return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]);
tokenBilling() tente de traiter un paiement avec jeton pour un montant donné
setPaymentMethod() cette méthode est utilisée pour définir la méthode de paiement dans la classe du pilote, cela est nécessaire dans les classes de passerelle où il y a plusieurs options de méthode de paiement dans la passerelle, par exemple. Carte de crédit, virement bancaire.
La classe BaseDriver elle-même contient plusieurs méthodes d'assistance qui permettent la création d'enregistrements de paiement dans Invoice Ninja, ceux-ci sont définis comme suit:
// Ne traduisez pas cette partie avec les balises PHP et retournez-public function storeGatewayToken(array $data, array $additional = []): ?ClientGatewayToken
Voici comment appeler cette méthode en utilisant un exemple concret:
$data = [
'gateway_id' => 1,
'client_id' => 2
];
$clientGatewayToken = $this->storeGatewayToken($data, ['user' => $this->user]);
Notez que voyez pouvez ajouter des informations supplémentaires en utilisant le deuxième argument de cette fonction, qui est facultatif.
Cette méthode est utilisée pour stocker un jeton généré par une passerelle de paiement, elle nécessite un tableau de paramètres avec la définition suivante :
[
'jeton', // (chaîne de caractères),
'identifiant_methode_paiement', // (ex : GatewayType::CREDIT_CARD),
'metadonnees_paiement', // Objet stdClass défini ci-dessous
]
$payment_meta = new \stdClass; $payment_meta->exp_month = (string) $method->card->exp_month; $payment_meta->exp_year = (string) $method->card->exp_year; $payment_meta->brand = (string) $method->card->brand; $payment_meta->last4 = (string) $method->card->last4; $payment_meta->type = GatewayType::CREDIT_CARD;
Pour améliorer l'abstraction, nous encourageons le développement de l'implémentation de la passerelle de paiement réelle dans son propre espace de noms. Une fois que vous avez terminé le traitement d'une réponse de passerelle, vous devrez effectuer un travail supplémentaire, cela pourrait inclure :
1. Retourner une réponse de paiement réussie à l'utilisateur final
2. Traiter un remboursement
3. Stocker un jeton de passerelle client
4. Traiter une réponse de paiement échoué à l'utilisateur final
Invoice ninja fournit le point d'entrée pour ceux-ci dans la classe BaseDriver, les données exactes requises sont spécifiées comme ci-dessus, le reste est fusionné à partir des données déjà présentes dans le pilote lui-même.
#### 1. Gérer une réponse de paiement réussie
Invoice ninja utilise une petite classe de liaison appelée PaymentHash, qui relie les métadonnées de paiement à un hachage. Une fois que vous êtes revenu de votre passerelle, vous devrez réhydrater l'objet de hachage de paiement. Il vous sera retourné par la passerelle dans la variable de demande `payment_hash` en utilisant une recherche binaire comme suit :
```php
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
À ce stade, vous devrez créer un enregistrement de paiement, cela peut être transmis directement à la méthode BaseDriver définie ci-dessous
public function createPayment(array $data, $status = Payment::STATUS_COMPLETED): Payment
Note : La traduction n'est pas requise pour les blocs de code, les balises HTML et les attributs en ligne tels que les liens et les images.
Le tableau de données ici nécessite les propriétés suivantes à être transmises depuis votre pilote de paiement personnalisé
[
'gateway_type_id', // (c.-à-d. GatewayType::CREDIT_CARD)
'amount', // (float) voir ci-dessous
'payment_type', // (c.-à-d. PaymentType::CREDIT_CARD_OTHER)
'transfaction_reference',
]
L'élément clé du montant est issu du hachage de paiement, la requête suivante devrait être utilisée pour déterminer le montant
array_sum(array_column($payment_hash->invoices(), 'montant')) + $payment_hash->total_frais;
N.B. Dans le bloc de code ci-dessus, j'ai traduit uniquement le commentaire. Ne traduisez pas le code dans les blocs de code.
En plus de créer l'enregistrement de paiement, nous recommandons fortement de consigner la sortie complète de la passerelle pour permettre le débogage à des fins futures, cela se fait via SystemLogger::job() qui est défini comme suit
public function __construct(array $log, int $category_id, int $event_id, int $type_id, ?Client $client)
L'objet tableau est la réponse de la passerelle, regroupée avec toutes autres métadonnées que vous souhaitez ajouter. Les propriétés restantes sont les valeurs constantes définies dans SystemLog, celles-ci définissent la catégorie, l'événement et le type de journal. N'hésitez pas à créer des catégories supplémentaires en utilisant le modèle présent dans la classe SystemLog.
La méthode de remboursement est implémentée dans votre classe PaymentDriver avec la méthode suivante
public function refund(Payment $payment, $refund_amount, $return_client_response = false);
Vous pourriez avoir besoin de la classe $payment pour passer la transaction_reference à votre passerelle, avec le refund_amount, l'objet de retour ici est un simple tableau de données en cas de succès, ou lancer une exception avec un message approprié.
Une fois que vous avez généré un jeton de passerelle, vous devrez le stocker. Une méthode d'assistance dans le BaseDriver est définie ici :
public function storeGatewayToken(array $data, array $additional = []): ?ClientGatewayToken
Les propriétés requises pour le tableau de données sont les suivantes :
[
'jeton',
'identifiant_methode_paiement',
'meta_paiement',
'identifiant_methode_paiement', // par exemple. GatewayType::CREDIT_CARD
'reference_client_gateway', // facultatif
]
Un message d'erreur générique est fourni lorsqu'une erreur fatale de passerelle se produit pendant le traitement d'un paiement
throw new PaymentFailed('Échec du traitement du paiement.', 500);
Le long de cette exception, il est également requis que vous lanciez un PaymentFailureMailer::job() défini comme suit
PaymentFailureMailer::dipatch($client, $erreur, $entreprise, $payment_hash)
Want to contribute? Edit this page on GitHub!