Zahlungs-Gateways erstellen: Unterschied zwischen den Versionen

Aus sourceDESK Wiki
Wechseln zu: Navigation, Suche
 
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 4: Zeile 4:
 
Im Ordner '''modules/payment''' liegen alle Zahlungs-Gateways. Jedes Zahlungsgateway hat dort einen Ordner mit einem Namen für dieses (nur Kleinbuchstaben; natürlich können Abkürzungen verwaltet werden). Dieser kurze Name wird im Folgenden als ''Kurzname'' bezeichnet.
 
Im Ordner '''modules/payment''' liegen alle Zahlungs-Gateways. Jedes Zahlungsgateway hat dort einen Ordner mit einem Namen für dieses (nur Kleinbuchstaben; natürlich können Abkürzungen verwaltet werden). Dieser kurze Name wird im Folgenden als ''Kurzname'' bezeichnet.
  
In einem Ordner eines Gateways wiederum muss sich eine Datei mit dem Kurznamen des Gateways und der Endung ''.php'' befinden. Diese Datei stellt die Hauptdatei des Gateways dar. Außerdem muss ein Ordner ''language'' für den Support mehrerer Sprachen existieren. Für [[Smarty]]-Templates kann zum Beispiel ein seperater Ordner ''templates'' angelegt werden.
+
In einem Ordner eines Gateways wiederum muss sich eine Datei mit dem Kurznamen des Gateways und der Endung ''.php'' befinden. Diese Datei stellt die Hauptdatei des Gateways dar. Außerdem muss ein Ordner ''language'' existieren, wenn Sie mehrere Sprachen unterstützen möchten. Für [[Smarty]]-Templates kann zum Beispiel ein separater Ordner ''templates'' angelegt werden.
  
 
== Aufbau der Hauptdatei ==
 
== Aufbau der Hauptdatei ==
Zeile 19: Zeile 19:
 
</source>
 
</source>
  
Für jede Gateway-Klasse sollte ein eigener Konstruktor geschrieben werden. Dieser muss den Konstruktor von ''PaymentGateway'' (der Oberklasse) aufrufen und sollte die aktuelle Sprache festsetzen. Außerdem müssen die Sprachdateien geladen werden. Wir lernen hier den Ausnahmen-Typ ''ModuleException'' kennen. Ein Wurf einer solchen Ausnahme wird das Modul nicht laden sondern ignorieren.
+
Für jede Gateway-Klasse sollte ein eigener Konstruktor geschrieben werden. Dieser muss den Konstruktor von ''PaymentGateway'' (der Oberklasse) aufrufen und sollte die aktuelle Sprache festsetzen. Außerdem müssen die Sprachdateien geladen werden. Wir lernen hier den Ausnahmen-Typ ''ModuleException'' kennen. Ein Wurf einer solchen Ausnahme wird das Modul nicht laden, sondern ignorieren.
  
 
<source lang="php">
 
<source lang="php">
Zeile 77: Zeile 77:
  
 
== getPaymentHandler() ==
 
== getPaymentHandler() ==
...
+
Diese Methode kann definieren, welcher Code ausgeführt werden soll, wenn die URL <code>SOURCEDESK_URL/credit/pay/GATEWAY_NAME</code> aufgerufen wird.
  
 
== makeCashboxPayment($hash) ==
 
== makeCashboxPayment($hash) ==
...
+
Diese Methode startet den Zahlungsvorgang für eine Cashbox-Zahlung mit dem Hash ''$hash''.
  
 
== getIpnHandler() ==
 
== getIpnHandler() ==
...
+
Diese Methode wird aufgerufen, wenn die URL <code>SOURCEDESK_URL/ipn/GATEWAY_NAME</code> aufgerufen wird.
  
 
== Gebühren ==
 
== Gebühren ==
...
+
Es ist dem Administrator für jedes Gateway individuell möglich, Gebühren einzustellen. Diese kann er sowohl prozentual als auch fix angeben (natürlich auch beides gleichzeitig). Bei einer Einstellung beider Gebühren-Typen für ein Gateway wird zuerst der prozentuale Wert gebildet und dann von diesem der fixe. Außerdem ist es möglich einzustellen, ob der vom Kunden eingegebene Betrag inklusive oder exklusive Gebühren sein soll.
 +
 
 +
Für die Gebührenrechnung gibt es zwei Methoden, der innerhalb der Klasse verfügbar sind. Die erste Methode ist ''addFees'', sie erwartet zwei Parameter. Der erste beinhaltet den Betrag ohne Gebühren, der zweite ist ein Boolean (true/false) und gibt an, ob der Betrag noch konvertiert werden muss. Für die Konvertierung wird die aktuell eingestellte Währung angenommen und der Betrag dann in die Basiswährung konvertiert. Außerdem vorhanden ist die Methode ''deductFees'', sie erwartet nur einen Parameter, nämlich den Betrag. Eine automatische Konvertierung kann hier nicht erfolgen.
 +
 
 +
Für die Anzeige der Gebühren sollte am besten zum Beispiel an das Ende des Zahlungs-Buttons eine entsprechende Information angehangen werden. Diese ist standardmäßig wie folgt realisiert:
 +
 
 +
<source lang="php">
 +
$fees = $addon = "";
 +
if($this->settings['excl'] == 1)
 +
$addon = "_EXCL";
 +
if($this->settings['fix'] != 0 && $this->settings['percent'] != 0)
 +
$fees = " " . str_replace(Array("%p", "%a"), Array($nfo->format($this->settings['percent'], 2, true), $cur->infix($nfo->format($cur->convertAmount(null, $this->settings['fix']), 2))), $lang['CREDIT']['FEES_BOTH' . $addon]);
 +
else if($this->settings['fix'] != 0)
 +
$fees = " " . str_replace(Array("%p", "%a"), Array($nfo->format($this->settings['percent'], 2, true), $cur->infix($nfo->format($cur->convertAmount(null, $this->settings['fix']), 2))), $lang['CREDIT']['FEES_FIX' . $addon]);
 +
else if($this->settings['percent'] != 0)
 +
$fees = " " . str_replace(Array("%p", "%a"), Array($nfo->format($this->settings['percent'], 2, true), $cur->infix($nfo->format($cur->convertAmount(null, $this->settings['fix']), 2))), $lang['CREDIT']['FEES_PERCENT' . $addon]);
 +
</source>
 +
 
 +
Es ist übrigens beispielsweise in der Methode ''getPaymentForm()'' auch sehr einfach, den Betrag clientseitig um die Gebühren zu erhöhen. Hierfür ein kleiner Ausschnitt JavaScript:
 +
 
 +
<source lang="javascript">
 +
paypalFeesAdded = 0;
 +
paypalFeesAdded = 0;
 +
function addPayPalFees() {
 +
<?php if($this->settings['excl'] == 1){ ?>
 +
if(!paypalFeesAdded){
 +
            var percent = <?=$this->settings['percent']; ?>;
 +
            var fix    = Number(<?=$cur->convertAmount(null, $this->settings['fix']); ?>);
 +
            var value  = Number(document.getElementById("paypal_amount").value.replace(',', '.'));
 +
 
 +
value += Math.ceil(value * percent) / 100;
 +
value += fix;
 +
value  = String(value);
 +
document.getElementById("paypal_amount").value = value<?=$CFG['NUMBER_FORMAT'] == "de" ? ".replace('.', ',')" : ""; ?>;
 +
paypalFeesAdded = 1;
 +
}
 +
<?php } ?>
 +
}
 +
</source>
 +
 
 +
Dafür muss das Betrags-Feld natürlich die ID ''paypal_amount'' haben und der Zahlungs-Button als onClick-Handler ''addPayPalFees()''.
 +
 
 +
Mit einer Zeile Code im Konstruktor kann das Gebührensystem übrigens für dieses Gateway deaktiviert werden:
 +
 
 +
<source lang="php">
 +
$this->no_fees = true;
 +
</source>
  
 
== Zahlungs-Log ==
 
== Zahlungs-Log ==
Zeile 102: Zeile 148:
  
 
Als ''$data'' verwenden Sie am besten die eingegeben Rohdaten, indem Sie zum Beispiel ''$_POST'' dumpen. Achten Sie hierbei unbedingt auf die Entfernung langer oder unnötiger Werte, um das Zahlungs-Log im Adminbereich nicht zu sprengen. Für ''$log'' ist normalerweise ein eigener String vorgesehen, der die Aktionen des IPN-Handlers beschreibt. (Zeilenumbruch durch \n) Es eignet sich hierfür eine try-catch-Struktur.
 
Als ''$data'' verwenden Sie am besten die eingegeben Rohdaten, indem Sie zum Beispiel ''$_POST'' dumpen. Achten Sie hierbei unbedingt auf die Entfernung langer oder unnötiger Werte, um das Zahlungs-Log im Adminbereich nicht zu sprengen. Für ''$log'' ist normalerweise ein eigener String vorgesehen, der die Aktionen des IPN-Handlers beschreibt. (Zeilenumbruch durch \n) Es eignet sich hierfür eine try-catch-Struktur.
 
== Cashbox ==
 
...
 
 
== Sprachsystem ==
 
...
 
  
 
== Weiteres ==
 
== Weiteres ==
Zeile 115: Zeile 155:
 
$this->admin_warning = "Warntext";
 
$this->admin_warning = "Warntext";
 
</source>
 
</source>
 +
 +
== Beispiel-Integrationen ==
 +
Sie finden Beispiel-Integrationen in ''modules/gateways/''.

Aktuelle Version vom 5. Oktober 2018, 11:09 Uhr

Sie können in das System weitere modulare Zahlungs-Gateways einbauen, über welche Zahlungen Ihrer Kunden abgewickelt werden können. Die Integration ist recht simpel möglich.

Grundaufbau

Im Ordner modules/payment liegen alle Zahlungs-Gateways. Jedes Zahlungsgateway hat dort einen Ordner mit einem Namen für dieses (nur Kleinbuchstaben; natürlich können Abkürzungen verwaltet werden). Dieser kurze Name wird im Folgenden als Kurzname bezeichnet.

In einem Ordner eines Gateways wiederum muss sich eine Datei mit dem Kurznamen des Gateways und der Endung .php befinden. Diese Datei stellt die Hauptdatei des Gateways dar. Außerdem muss ein Ordner language existieren, wenn Sie mehrere Sprachen unterstützen möchten. Für Smarty-Templates kann zum Beispiel ein separater Ordner templates angelegt werden.

Aufbau der Hauptdatei

In der Hauptdatei muss eine Klasse definiert werden, welche einen einmaligen Namen tragen und die abstrakte Klasse PaymentGateway erweitern muss.

class PayPalPG extends PaymentGateway {

Es wird eine statische Variable benötigt, welchen den Kurznamen der Klasse enthält (theoretisch darf dieser auch abweichen, der Übersichtlichkeit halber sollte dieser aber gleich sein):

public static $shortName = "paypal";

Für jede Gateway-Klasse sollte ein eigener Konstruktor geschrieben werden. Dieser muss den Konstruktor von PaymentGateway (der Oberklasse) aufrufen und sollte die aktuelle Sprache festsetzen. Außerdem müssen die Sprachdateien geladen werden. Wir lernen hier den Ausnahmen-Typ ModuleException kennen. Ein Wurf einer solchen Ausnahme wird das Modul nicht laden, sondern ignorieren.

public function __construct($language) {
	parent::__construct(self::$shortName);
	$this->language = $language;
 
        if(!include(dirname(__FILE__) . "/language/$language.php"))
        	throw new ModuleException();
        if(!is_array($addonlang) || !isset($addonlang["NAME"]))
        	throw new ModuleException();
 
        $this->lang = $addonlang;
}

Einstellungen

Es können Einstellungen definiert werden, die durch den Administrator zu tätigen sind, wenn er das Modul in der Administration konfiguriert. Nachfolgend sehen Sie, wie Sie diese Einstellungen im Konstruktor der Gateway-Klasse definieren.

$this->options = Array(
	"text" => Array("type" => "text", "name" => "Textfeld", "default" => "Standard", "placeholder" => "Hier irgendwas eingeben", "help" => "Das steht drunter"),
	"check" => Array("type" => "checkbox", "description" => "Daneben", "default" => true, "help" => "Das steht drunter"),
);

Sie sehen hier ein multidimensionales Array. Als Key der Arrays in der zweiten Dimension wird ein Options-Name verwendet, dieser ist beliebig. Der Wert ist wiederum ein Array. Darin befindet sich u.a. die Eigenschaft type, sie kann text (Textfeld) oder checkbox sein und bestimmt, welches Steuerelement angezeigt wird. Die weiteren Parameter sind optional, wobei natürlich zumindest name bzw. description angegeben werden sollte.

Der Zugriff auf die getätigten Einstellungen kann dann innerhalb der Klasse recht simpel erfolgen mit:

$this->settings[$key];

Aktivieren / Deaktivieren

Es ist möglich, bestimmte Aktionen beim Aktivieren bzw. Deaktivieren eines Gateways auszuführen. Dafür können Sie eine Methode nach folgendem Schema erstellen:

public function deactivate() {
	global $db, $CFG;
	parent::deactivate();
 
	$db->query("DROP TABLE `" . $CFG['DB']['PREFIX'] . "gatewayTable`;");
}

Wichtig ist hier das Aufrufen der entsprechenden Methode der Oberklasse. Für das Aktivieren kann äquivalent dazu die Methode activate() geschrieben werden.

getPaymentForm()

Diese Methode soll den HTML-Code zurückgeben, der auf der Seite zum Einzahlen von Guthaben angezeigt werden soll. Dieser ist meist eine HTML-Form.

public function getPaymentForm() {
	return "<center>Derzeit ist diese Methode nicht implementiert.</center>";
}

getPaymentHandler()

Diese Methode kann definieren, welcher Code ausgeführt werden soll, wenn die URL SOURCEDESK_URL/credit/pay/GATEWAY_NAME aufgerufen wird.

makeCashboxPayment($hash)

Diese Methode startet den Zahlungsvorgang für eine Cashbox-Zahlung mit dem Hash $hash.

getIpnHandler()

Diese Methode wird aufgerufen, wenn die URL SOURCEDESK_URL/ipn/GATEWAY_NAME aufgerufen wird.

Gebühren

Es ist dem Administrator für jedes Gateway individuell möglich, Gebühren einzustellen. Diese kann er sowohl prozentual als auch fix angeben (natürlich auch beides gleichzeitig). Bei einer Einstellung beider Gebühren-Typen für ein Gateway wird zuerst der prozentuale Wert gebildet und dann von diesem der fixe. Außerdem ist es möglich einzustellen, ob der vom Kunden eingegebene Betrag inklusive oder exklusive Gebühren sein soll.

Für die Gebührenrechnung gibt es zwei Methoden, der innerhalb der Klasse verfügbar sind. Die erste Methode ist addFees, sie erwartet zwei Parameter. Der erste beinhaltet den Betrag ohne Gebühren, der zweite ist ein Boolean (true/false) und gibt an, ob der Betrag noch konvertiert werden muss. Für die Konvertierung wird die aktuell eingestellte Währung angenommen und der Betrag dann in die Basiswährung konvertiert. Außerdem vorhanden ist die Methode deductFees, sie erwartet nur einen Parameter, nämlich den Betrag. Eine automatische Konvertierung kann hier nicht erfolgen.

Für die Anzeige der Gebühren sollte am besten zum Beispiel an das Ende des Zahlungs-Buttons eine entsprechende Information angehangen werden. Diese ist standardmäßig wie folgt realisiert:

$fees = $addon = "";
if($this->settings['excl'] == 1)
	$addon = "_EXCL";
if($this->settings['fix'] != 0 && $this->settings['percent'] != 0)
	$fees = " " . str_replace(Array("%p", "%a"), Array($nfo->format($this->settings['percent'], 2, true), $cur->infix($nfo->format($cur->convertAmount(null, $this->settings['fix']), 2))), $lang['CREDIT']['FEES_BOTH' . $addon]);
else if($this->settings['fix'] != 0)
	$fees = " " . str_replace(Array("%p", "%a"), Array($nfo->format($this->settings['percent'], 2, true), $cur->infix($nfo->format($cur->convertAmount(null, $this->settings['fix']), 2))), $lang['CREDIT']['FEES_FIX' . $addon]);
else if($this->settings['percent'] != 0)
	$fees = " " . str_replace(Array("%p", "%a"), Array($nfo->format($this->settings['percent'], 2, true), $cur->infix($nfo->format($cur->convertAmount(null, $this->settings['fix']), 2))), $lang['CREDIT']['FEES_PERCENT' . $addon]);

Es ist übrigens beispielsweise in der Methode getPaymentForm() auch sehr einfach, den Betrag clientseitig um die Gebühren zu erhöhen. Hierfür ein kleiner Ausschnitt JavaScript:

paypalFeesAdded = 0;
paypalFeesAdded = 0;
function addPayPalFees() {
	<?php if($this->settings['excl'] == 1){ ?>
	if(!paypalFeesAdded){
    	        var percent = <?=$this->settings['percent']; ?>;
    	        var fix     = Number(<?=$cur->convertAmount(null, $this->settings['fix']); ?>);
    	        var value   = Number(document.getElementById("paypal_amount").value.replace(',', '.'));
 
		value += Math.ceil(value * percent) / 100;
		value += fix;
		value  = String(value);
		document.getElementById("paypal_amount").value = value<?=$CFG['NUMBER_FORMAT'] == "de" ? ".replace('.', ',')" : ""; ?>;
		paypalFeesAdded = 1;
	}
	<?php } ?>
}

Dafür muss das Betrags-Feld natürlich die ID paypal_amount haben und der Zahlungs-Button als onClick-Handler addPayPalFees().

Mit einer Zeile Code im Konstruktor kann das Gebührensystem übrigens für dieses Gateway deaktiviert werden:

$this->no_fees = true;

Zahlungs-Log

Es gibt ein Log-System für Zahlungs-Gateways, welches für das Logging von IPN-Anfragen gedacht ist. Diese Funktion ist jedoch standardmäßig deaktiviert und muss pro Gateway aktiviert werden.

$this->log = true;

Das Einfügen muss manuell mit einer Datenbank-Query erfolgen, als Vorlage können Sie diese verwenden:

$db->query("INSERT INTO " . $CFG['DB']['PREFIX'] . "payment_logs (`data`, `log`, `time`, `gateway`) VALUES ('$data', '$log', " . time() . ", '" . self::$shortName . "')");

Als $data verwenden Sie am besten die eingegeben Rohdaten, indem Sie zum Beispiel $_POST dumpen. Achten Sie hierbei unbedingt auf die Entfernung langer oder unnötiger Werte, um das Zahlungs-Log im Adminbereich nicht zu sprengen. Für $log ist normalerweise ein eigener String vorgesehen, der die Aktionen des IPN-Handlers beschreibt. (Zeilenumbruch durch \n) Es eignet sich hierfür eine try-catch-Struktur.

Weiteres

Es ist möglich, im Modal zur Gateway-Konfiguration unter den Einstellungen einen Text anzuzeigen. Dieser kann zum Beispiel wichtige Hinweise zur Konfiguration oder Warnungen enthalten. Die Definition sollte wie folgt im Konstruktor der Gateway-Klasse erfolgen:

$this->admin_warning = "Warntext";

Beispiel-Integrationen

Sie finden Beispiel-Integrationen in modules/gateways/.