Skip to main content

Documentation Index

Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt

Use this file to discover all available pages before exploring further.

Konfigurationen

Folgende Einstellungen sind relevant für die Konfiguration der Zahlungsart stripe:

Module

Folgende Module sind relevant für die Integration der Zahlungsart stripe im Bestellprozess:
  • $wsStripe - stripe-Zahlungsarten Modul
  • $wsCheckout - Checkout-Zustand, Adressen, Versand, Zahlung, Probleme, Summen
  • $wsActions - Aktionen erzeugen und auswerten
  • $wsAccount - Login-Status, E-Mail, Adressen, loadAddress()
  • $wsViews - Aktuelle URL, Zielseiten, View-URLs
  • $wsBasket - Warenkorb und Bestellübersicht
  • $wsConfig - Konfigurationswerte, zum Beispiel Anreden und Währung

Aktionen

Folgende Aktionen sind relevant für die Integration der Zahlungsart stripe:

Zusätzliche relevante Informationen

Folgende zusätzlichen Inhalte müssen für die Zahlungsart integriert werden.

Frontend-Integration

Stripe stellt ein eigenes JavaScript-SDK bereit, das in das Template eingebunden werden muss. Es übernimmt die Darstellung der Zahlungsfelder und die Kommunikation mit Stripe. HTML-Struktur
Folgender HTML-Block muss im Template plaziert werden:
  • #wsStripePaymentElement ist der Container, in den Stripe die Zahlungsfelder (z.B. Kreditkartennummer, PayPal-Button etc.) automatisch einbettet
  • Das Formular sendet beim Klick auf “Mit Stripe bezahlen” den Bezahlvorgang ab
<div id="wsStripePaymentElement">
    
</div>
<form method="post" action="{{= $wsViews.current.url() }}" id="wsCheckoutStripeConfirmForm">
    <input type="hidden" name="wsact" value="{{= $cActionCheckoutConfirm.id }}">
    <input type="hidden" name="wscsrf" value="{{= $cActionCheckoutConfirm.csrf }}">
    <input type="hidden" name="wstarget" value="{{= $wsViews.viewUrl('confirm.htm') }}">
    <button class="btn btn-success btn-block wsStripeOrderBtn" {{if not $wsCheckout.isValid}}disabled{{/if}}>
      Mit Stripe bezahlen
    </button>
</form>
JavaScript
Der folgenden Script-Block muss direkt nach dem HTML-Block eingefügt werden. Er muss in {{ autoescape “js” }} eingeschlossen sein, damit Template-Variablen im JavaScript-Kontext korrekt verarbeitet werden.
Der Ablauf im Script ist folgender:
  1. Stripe initialisieren - Das SDK wird mit den Zugangsdaten aus $wsStripe.configuration gestartet
  2. Zahlungsfelder anzeigen - Stripe rendert die Zahlungsauswahl (Kreditkarte, PayPal etc.) in den #wsStripePaymentElement-Container. Die Adresseingabefelder von Stripe werden dabei deaktiviert, weil die Adresse des Kunden bereits im Shop bekannt ist und automatisch übergeben wird.
  3. Bezahlung auslösen - Beim Absenden des Formulars werden die eingegebenen Zahlungsdaten zusammen mit der Rechnungsadresse aus $wsAccount an Stripe geschickt. Stripe gibt dafür ein Confirmation-Token zurück.
  4. Token an den Shop senden - Das Token wird an den Shop übermittelt, der damit den eigentlichen Zahlungsvorgang bei Stripe startet.
  5. Ergebnis verarbeiten - Schlägt die Zahlung fehl, wird eine Fehlermeldung angezeigt. Ist eine zusätzliche Bestätigung nötig (z.B. 3D Secure), übernimmt Stripe das automatisch.
  6. Weiterleitung - Nach erfolgreicher Zahlung wird der Kunde zur Bestellbestätigungsseite weitergeleitet.
{{ autoescape "js" }}
<script>
    {{ var $stripeConfig = $wsStripe.configuration }}
    const stripe = Stripe("{{= $stripeConfig.publishableKey }}", {
        stripeAccount: "{{= $stripeConfig.targetAccount }}"
    });

    const appearance = {
        theme: 'stripe', // Aussehen anpassbar, siehe Stripe Appearance API
    };

    const options = {
        mode: 'payment',
        amount: {{= $wsCheckout.getAmountInSmallestUnit($wsCheckout.sum.total) }},
        currency: '{{= lower($wsCheckout.sum.currency) }}',
        paymentMethodCreation: 'manual',
        appearance,
    };

    const elements = stripe.elements(options);

    // Adresseingabefelder von Stripe deaktivieren – die Adresse wird
    // weiter unten beim Absenden automatisch aus $wsAccount übergeben
    const paymentElement = elements.create('payment', {
        fields: {
            billingDetails: {
                name: 'never',
                email: 'never',
                phone: 'never',
                address: {
                    line1: 'never',
                    line2: 'never',
                    city: 'never',
                    state: 'auto', // Bundesland ist in unseren Adressen nicht vorhanden
                    country: 'never',
                    postalCode: 'never'
                }
            }
        }
    });
    paymentElement.mount("#wsStripePaymentElement");

    document
        .querySelector("#wsCheckoutStripeConfirmForm")
        .addEventListener("submit", handleSubmit);

    async function handleSubmit(e) {
        e.preventDefault();
        setLoading(true);

        // Prüfen ob die Zahlungseingaben vollständig sind
        const {error: submitError} = await elements.submit();
        if (submitError) {
            showMessage(submitError.message);
            return;
        }

        // Zahlungsdaten + Rechnungsadresse an Stripe schicken,
        // Stripe gibt dafür ein Confirmation Token zurück
        const {error, confirmationToken} = await stripe.createConfirmationToken({
            elements,
            params: {
                payment_method_data: {
                    billing_details: {
                        {{ foreach $addr in $wsAccount.addresses }}
                            {{if $addr.id==$wsCheckout.selectedBillAddress}}
                        address: {
                            city: "{{=$addr.city}}",
                            country: "{{=$addr.country}}",
                            line1: "{{=$addr.street}}",
                            line2: "",
                            postal_code: "{{=$addr.zip}}",
                        },
                        email: "{{ if $wsCheckout.guestMail }}{{= $wsCheckout.guestMail }}{{ else }}{{= $wsAccount.email }}{{ /if }}",
                        name: "{{=$addr.firstName}} {{=$addr.lastName}}",
                        phone: "{{= $addr.phone }}",
                            {{ /if }}
                        {{ /foreach }}
                    }
                }
            }
        });

        if (error) {
            showMessage(error.message);
            return;
        }

        // Confirmation Token an den Shop schicken, der startet damit den Zahlungsvorgang
        var action = $('#confirmForm').attr('action');
        var payload = $('#confirmForm').serialize();
        payload += `&confirmationToken=${confirmationToken.id}`;

        const response = await fetch(action, {
            method: 'post',
            body: payload
        });

        const dataContentType = response.headers.get("content-type");
        if (dataContentType && !dataContentType.includes("application/json")) {
            // Antwort ist kein JSON (z.B. wenn AGB nicht akzeptiert wurden) – Seite neu laden
            return;
        }

        const data = await response.json();
        const { success } = data;

        if (success === false) {
            // Zahlung abgelehnt – Fehlerdetails unter: https://docs.stripe.com/testing#declined-payments
            const {error_code, decline_code} = data;
            showMessage(`Zahlung fehlgeschlagen: ${error_code} ${decline_code}`);
            setLoading(false);
            return;
        }

        // Falls eine zusätzliche Bestätigung nötig ist (z.B. 3D Secure),
        // übernimmt Stripe das automatisch
        const { clientSecret, status } = data;
        if (status === "requires_action") {
            const { error } = await stripe.handleNextAction({ clientSecret });
            if (error) {
                showMessage(error.message);
                setLoading(false);
                return;
            }
        }

        setLoading(false);
        // Zahlung erfolgreich – zur Bestellbestätigung weiterleiten
        window.location.href = "{{= $wsViews.viewUrl('confirm.htm', {wsPayment: 'stripe', stripe_action: 'return'}) }}";
    }

    // ------- UI-Hilfsfunktionen -------

    function showMessage(messageText) {
        // TODO: Fehlermeldung anzeigen
    }

    function setLoading(isLoading) {
        let wsStripeOrderBtn = document.querySelectorAll(".wsStripeOrderBtn");
        wsStripeOrderBtn.forEach(btn => btn.disabled = isLoading);
        // TODO: Lade-Indikator ein-/ausblenden
    }
</script>
{{ /autoescape }}