Home > Web Entwicklung > Paypal subscriptions – Abonnements in Java integrieren

Paypal subscriptions – Abonnements in Java integrieren

Für einen Kunden habe ich in der letzten Woche die Zahlungsabwicklung von Abonnements über Paypal integriert. Der Web Nutzer kann auf diesem einfachen Wege die Vorzüge vom Premiumdiensten nutzen. Der Vorteil hierbei ist: Der potentielle Käufer muss seine Kreditkarten- bzw. Kontodaten nicht an eine “nicht vertrauenswürdige” Seite weitergeben, sondern nutzt die bereits bei Paypal hinterlegten Daten. Ist der Käufer noch keine Paypal Kunde, ist eine vorige Anmeldung allerdings notwendig.

Der grundlegende Mechanismus für Subscriptions ist denkbar einfach. An einer beliebigen Stelle in unserer Webapplikation wird der Benutzer per link oder submit button an die Paypal Seite geleitet. Alle relevanten Daten für die Zahlung werden entweder als GET Parameter (Link) oder POST Parameter (Button) übertragen. Dazu zählen vor allem folgende Angaben:

  • Abonnementinterval (1 Tag, 4 Wochen oder 12 Monate)
  • Betrag pro Abonnementinterval
  • Währung
  • Paypal Id des Verkäufers
  • Rechnungsnummer
  • Automatische Verlängerung (ja/nein)
  • Beliebige zusätzliche Informationen

Sollte der Benutzer noch kein Paypal Kunde sein, muss er sich bei Paypal erst registrieren. Um dies so einfach wie möglich zu gestalten können wir zusätzlich Benutzerinformationen mitsenden, die Paypal in das Registrierungsformular einfügt.

  • Name, Nachname
  • Adress(Strasse, PLZ, Stadt, Land)
  • Email Adresse

Damit wir zum Testen unserer Applikation kein Vermögen hinblättern müssen, stellt Paypal eine sogenannte Sandbox zur Verfügung. Eine eigene Developer Sandbox kann man sich hier einrichten. Diese Sandbox stellt die kompletten Funktionen von Paypal zur Verfügung. Mit zwei Unterschieden: Es fließt kein echtes Geld und es gibt nur die Benutzer, die wir selbst angelegt haben. Um also einen Zahlungsfluss zu simulieren müssen in der Sandbox mindestens zwei Benutzer angelegt sein (Verkäufer und Käufer). Zum Erzeugen eines einfachen Bezahlknopfes eignet sich die Paypal Button Factory, welche unter Merchant Services im Paypal Menü des Verkäufers erreichbar ist. Doch es gibt auch Gründe gegen einen statischen Bezahlknopf auf der Webseite. Angenommen wir wollen mehrere Abonnements verkaufen, die sich je nach Laufzeit im Preis unterscheiden. Wäre es da nicht besser ein eigenes Formular zu erstellen, welches dem Benutzer die komplette Auswahl unserer Produkte anzeigt? Nachdem sich der Benutzer für eines unserer Abonnements entschieden hat, überträgt er seine Auswahl per druck auf den Bezahlknopf. Unsere Webapplikation wertet diese Informationen aus und leitet den Benutzer per redirect auf die Paypal Seite um. Dazu muss die URL mit sämtlichen Zahlungsinformationen dynamisch erzeugt werden. Hier eine Beispielimplementierung:

public String getPurchaseUrl() throws EncoderException {
	StringBuffer urlBuffer = new StringBuffer("https://www.sandbox.paypal.com/cgi-bin/webscr");
	urlBuffer.append("?no_note=1"); // Abonnements unterstützen keine Notizen
	urlBuffer.append("&a3=9.99"); // Der Preis des Abonnements
	urlBuffer.append("&t3=M"); // Intervall Einheit = Monate
	urlBuffer.append("&p3=1"); // Intervall Länge = 1 (Monat)
	urlBuffer.append("&business=verkaeufer@deine.url.de"); // Die email adresse für den verkäufer account bei paypal
	urlBuffer.append("&cmd=_xclick-subscriptions"); // Wir wollen eine abonnement
	urlBuffer.append("&src=1"); // Abonnement verlängert sich automatisch
	urlBuffer.append("&currency_code=EUR"); // Wir nehmen Zahlungen in Euro entgegen
	urlBuffer.append("&invoice=Rechnungsnummer"); // Hier kann eine Rechnungsnummer vergeben werden
	urlBuffer.append("&lc=DE"); // Die Zielseite soll in deutscher Sprache angezeigt werden
	urlBuffer.append("&no_shipping=1"); // Wir brauchen keine Versandadresse, denn wir verkaufen virtuelle Güter oder Dienstleistungen
	URLCodec encoder = new URLCodec();
	return encoder.encode(urlBuffer.toString());
}

Für das URL Encoding, welches alle Sonderzeichen in übertragbare Zeichen umwandelt, verwende ich die commons-codec Bibliothek von Apache Commons.

Die geladene Paypal Seite enthält nun alle Zahlungsinformationen. Der Potentielle Käufer muss sich lediglich mit seinem Paypal Benutzernamen anmelden und die Zahlung bestätigen. Ist die Automatische Rückleitung aktiviert, landet der Benutzer danach wieder auf unserer Seite. Die Aktivierung kann im Paypal Menu des Verkäufers unter “Profile ->Website Payment Preferences” eingestellt werden. Dazu wählt man den Radiobutton “Auto Return ON” und trägt unter “Return URL” die entsprechende Url ein, an die der Benutzer weitergeleitet werden soll. Mit dieser URL überträgt Paypal eine Transaktions Id, wenn in den Einstellungen zusätzlich noch “Payment Data Transfer” auf “On” gesetzt wurde. Die Dokumentation für PDT finden man auf der Paypal Developer Seite. Paypal erwartet darauf hin, dass unsere Webapplikation folgende Informationen zurück sendet:

  • TransaktionsId
  • Identitätstoken
  • Kommando

Die TransaktionsId ist die eben empfangene Id. Der Identitätstoken kann an der Stelle eingesehen werden, wo “Payment Data Transfer” angeschaltet wurde. Dies stellt sicher, dass Zahlungsinformationen nicht an unberechtigte Personen gesendet werden. Das Kommando muss den den Wert “_notify-synch” enthalten. Hier ein Beispiel, wie die Implementierung aussehen könnte. Für den Post Request zurück an Paypal habe ich die commons-httpclient Bibliothek von Apache Commons verwendet.

/**
 * Verabeitet Paypals Payment Data Transfer
 *
 * @param txId The transactionId
 * @return
 */
public void handleCallback(long txId) {
	Map<String,Object> params = new HashMap<String, Object>();
	params.put("cmd","_notify_synch");
	params.put("tx", txId);
	params.put("at", "IDENTITY_TOKEN");
	try {
		PostMethod method = doPostRequest("https://www.sandbox.paypal.com/cgi-bin/webscr", params);
		String responseBody = method.getResponseBodyAsString();
		if(responseBody != null) {
			if(responseBody.startsWith("SUCCESS")) {
				// Super, alles hat geklappt
				// Erfolgsnachricht anzeigen
			} else if(responseBody.startsWith("FAIL")) {
				// Die Zahlung war nicht korrekt durchgeführt
				// Fehlernachricht anzeigen
			} else {
				// Irgendwas ging richtig in die Hose
				// Fehlerbehandlung
			}
		} else {
 			// Das war auch nicht korrekt
	 		// Fehlerbehandlung
 		}
	} catch (HttpException e) {
		// Error sending PDT response
	} catch (IOException e) {
		// Error sending PDT response
	}
}
/**
 * Does a POST request to the given url and the given parameter map
 *
 * @param url
 * @param params
 * @return The method containing the response
 * @throws HttpException
 * @throws IOException
 */
public PostMethod doPostRequest(String url, Map<String, Object > params)
 	throws HttpException, IOException {
		HttpClient client = new HttpClient();
		HttpConnectionManager conManager = client.getHttpConnectionManager();
		HttpClientParams clientParams = client.getParams();
		clientParams.setConnectionManagerTimeout(2000);
		HttpConnectionManagerParams managerParams = conManager.getParams();
		managerParams.setConnectionTimeout(5000);
		managerParams.setSoTimeout(5000);
		PostMethod method = new PostMethod();
		method.setURI(new URI(url, false));
		HttpMethodParams paramsM = method.getParams(); // Wiederholungen unterdrücken
		paramsM.setParameter(HttpMethodParams.RETRY_HANDLER,
	 		new DefaultHttpMethodRetryHandler(0, false));
	Set<String> keys = params.keySet();
	for (String key : keys) {
		String value = (String) params.get(key);
		method.addParameter(key, value); // Setze Url Parameter
	}
	client.executeMethod(method); // Http Post ausführen
	return method;
}

Der Benutzer merkt vom Austausch der Zahlungsinformationen nichts, Es wird lediglich eine einfache Bestätigungsseite angezeigt. Auf dieser Seite wird dem Benutzer mitgeteilt wird, dass die Zahlung erfolgreich oder nicht erfolgreich war, und dass er von Paypal per Mail darüber benachrichtigt werden wird.

Paypal bietet zusätzlich die Möglichkeit, unsere Webapplikation asynchron über eingehende Zahlungen und/oder Kündigungen zu informieren. Die Mechanismus nennt sich IPN, was soviel bedeutet wie “sofortige Zahlungsavisierung”. Dieser Mechanismus ist deutlich robuster, als “Payment Data Transfer”. Doch dazu in später mehr.

  1. Roger
    11. Januar 2008, 23:38 | #1

    Sehr interessanter Artikel. Mit Freude gelesen.

  2. 20. Januar 2008, 19:41 | #2

    Vielen Dank für die erste Freudensbekundung hier um Blog.

  3. Rayden
    19. Mai 2008, 11:46 | #3

    Danke, dieser Artikel könnte mich retten :)

  1. Bisher keine Trackbacks