payment_plugins.rst 29 KB
Newer Older
oskar's avatar
oskar committed
1 2 3 4 5 6 7 8
Zahlungs-Plugins
================

.. |br| raw:: html

   <br />

Ein Zahlungs-Plugin definiert über den Knoten ``<PaymentMethod>`` in der ``info.xml`` eine oder mehrere
oskar's avatar
oskar committed
9 10 11 12
Zahlungsmethoden, die dann über eine Zuordnung zu Versandarten im Onlineshop für Bezahlvorgänge genutzt werden
können. |br|
Die grundsätzliche XML-Struktur einer Zahlungsmethode finden Sie im Abschnitt :ref:`label_infoxml_paymentmethode`
unter :doc:`infoxml`.
oskar's avatar
oskar committed
13 14 15 16

Grundlegendes
-------------

oskar's avatar
oskar committed
17
Jede Zahlungsmethode wird durch eine Payment-Klasse repräsentiert. Der Klassenname und die zugehörige Klassendatei
oskar's avatar
oskar committed
18 19 20
werden in der ``info.xml`` mit den Knoten ``<ClassName>`` und ``<ClassFile>`` festgelegt. Die Klassendatei muss sich
für eine erfolgreiche Validierung der Zahlungsmethode im Unterverzeichnis ``paymentmethod`` innerhalb des
Plugin-Verzeichnisses befinden. Bis einschließlich Version 4.x können die Bezeichner für Klassenname und Klassendatei
oskar's avatar
oskar committed
21
frei gewählt werden, während diese ab Version 5.0 der PSR-4-Spezifikation folgen müssen. |br|
oskar's avatar
oskar committed
22 23 24 25 26 27 28
Jede Payment-Klasse muss ab Version 5.0 das Interface ``JTL\Plugin\Payment\MethodInterface`` implementieren oder von
``JTL\Plugin\Payment\Method`` abgeerbt werden. Bis einschließlich Version 4.x müssen alle Payment-Klassen Unterklassen
von ``PaymentMethod`` (``/includes/modules/PaymentMethod.class.php``) sein. |br|
Über die Methoden der Payment-Klasse wird standardmäßig der komplette Zahlungsvorgang abgedeckt. Die Registrierung
weiterer Hooks für den Zahlungsprozess ist normalerweise nur notwendig, wenn durch die Zahlungsmethode weitergehende
Eingriffe in den Ablauf des Zahlungsvorganges oder des gesamten Bestellprozesses notwendig sind.

oskar's avatar
oskar committed
29 30
Implementation einer Payment-Klasse bis einschl. JTL-Shop Version 4.x
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
oskar's avatar
oskar committed
31 32 33 34 35 36 37 38 39 40 41 42

.. code-block:: php
   :emphasize-lines: 2

    <?php
    require_once PFAD_ROOT . PFAD_INCLUDES_MODULES . 'PaymentMethod.class.php';

    /**
     * Class SimplePayment.
     */
    class SimplePayment extends PaymentMethod
    {
mamazu's avatar
mamazu committed
43
        // ...
oskar's avatar
oskar committed
44 45
    }

oskar's avatar
oskar committed
46 47 48 49 50 51 52
Implementation einer Payment-Klasse ab JTL-Shop Version 5.0
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

.. hint::

    Im Weiteren wird von einer **Implementation für JTL-Shop Version 5.x** ausgegangen und nur soweit dies nicht auch
    sinngemäß für JTL-Shop Version 4.x gilt, explizit auf die Unterschiede eingegangen.
oskar's avatar
oskar committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66

.. code-block:: php
   :emphasize-lines: 4

    <?php
    namespace Plugin\jtl_example_payment\paymentmethod;

    use JTL\Plugin\Payment\Method;

    /**
     * Class SimplePayment.
     */
    class SimplePayment extends Method
    {
mamazu's avatar
mamazu committed
67
        // ...
oskar's avatar
oskar committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    }

Die Basis-Payment-Klasse ``JTL\Plugin\Payment\Method`` implementiert das benötigte Interface und stellt alle
grundlegenden Funktionen einer Zahlungsmethode zur Verfügung. Die eigene Payment-Klasse sollte deshalb immer von dieser
Basis-Klasse abgeerbt werden. |br|
Eine einfache Zahlungsmethode, die lediglich Informationen für eine Banküberweisung versendet, muss damit lediglich die
Methode ``preparePaymentProcess`` überschreiben.

.. code-block:: php

    <?php
    namespace Plugin\jtl_example_payment\paymentmethod;

    use JTL\Alert\Alert;
    use JTL\Mail\Mail\Mail;
    use JTL\Mail\Mailer;
    use JTL\Plugin\Payment\Method;
    use JTL\Session\Frontend;
    use JTL\Shop;
    use PHPMailer\PHPMailer\Exception;
    use stdClass;

    /**
     * Class SimplePayment
     * @package Plugin\jtl_example_payment\paymentmethod\src
     */
    class SimplePayment extends Method
    {
        protected const MAILTEMPLATE_SIMPLEPAYMENT = 'kPlugin_%d_SimplePaymentTransferData';

        /**
         * @inheritDoc
         */
        public function preparePaymentProcess($order): void
        {
            parent::preparePaymentProcess($order);

            $obj              = new stdClass();
            $obj->tkunde      = Frontend::getCustomer();
            $obj->tbestellung = $order;
            $tplKey           = \sprintf(self::MAILTEMPLATE_SIMPLEPAYMENT, $this->plugin->getID());

            /** @var Mailer $mailer */
            $mailer = Shop::Container()->get(Mailer::class);
            $mailer->getHydrator()->add('Bestellung', $order);

            $mail = new Mail();
            try {
                $mailer->send($mail->createFromTemplateID($tplKey, $obj));
            } catch (Exception $e) {
            } catch (\SmartyException $e) {
                Shop::Container()->getAlertService()->addAlert(
                    Alert::TYPE_ERROR,
                    __('Payment mail for Simple payment cant be send'),
                    'simplePaymentCantSendMail'
                );
            }
        }
    }

Die Methode ``preparePaymentProcess`` wird durch den Bestellabschluss nach Finalisierung der Bestellung aufgerufen und
startet den Bezahlvorgang der Zahlungsmethode. |br|
oskar's avatar
oskar committed
130 131
Im Beispiel wird das über die ``info.xml`` definierte E-Mail-Template für die Zahlungsmethode geladen und über den
Mailer-Service von JTL-Shop versendet.
oskar's avatar
oskar committed
132 133 134 135 136 137 138

Zahlung vor Bestellabschluss
----------------------------

Im Modus "Zahlung vor Bestellabschluss" wird beim Abschließen des Bestellvorganges durch den Kunden die Bestellung
nicht festgeschrieben, sondern lediglich in der aktuellen Kundensession gehalten, wenn der Bezahlvorgang gestartet wird.
Die Zahlungsmethode muss bei erfolgreicher Zahlung über einen Aufruf von ``/includes/modules/notify.php`` dafür sorgen,
oskar's avatar
oskar committed
139
dass der Kunde zum Bestellabschluss gelangt und die Bestellung festgeschrieben wird. Dies kann z. B. über eine
oskar's avatar
oskar committed
140 141
URL-Weiterleitung erfolgen. Die dafür notwendige URL kann mittels
:ref:`getNotificationURL <label_public-function-method-getNotificationURL>` ermittelt werden. |br|
oskar's avatar
oskar committed
142 143
Im Fehlerfall muss der Kunde zurück in den Bestellprozess geleitet werden, um die Bezahlung ggf. zu wiederholen oder
den Checkout mit einer anderen Zahlungsart fortsetzen zu können.
oskar's avatar
oskar committed
144 145 146

.. hint::

oskar's avatar
oskar committed
147
   Bei Zahlungsmethoden, die eine zeitversetzte Bestätigung der Zahlung via Webhook versenden, kann es passieren, dass
oskar's avatar
oskar committed
148
   die Bestellung nicht mehr festgeschrieben werden kann, da diese aufgrund einer abgelaufenen Kundensession bereits
oskar's avatar
oskar committed
149
   verfallen ist. In diesem Fall existiert dann eine Zahlung, zu der es keine Bestellung gibt! |br|
oskar's avatar
oskar committed
150 151 152
   Für solche Zahlungsmethoden sollte besser nur der Modus "Zahlung nach Bestellabschluss" gewählt werden.

Die "Zahlung vor Bestellabschluss" kann für die Zahlungsmethode über den XML-Parameter ``<PreOrder>1</PreOrder>``
oskar's avatar
oskar committed
153 154
voreingestellt werden. Dieser Wert lässt sich jedoch in den Einstellungen der Zahlungsmethode vom Betreiber des
Onlineshops nachträglich ändern.
oskar's avatar
oskar committed
155 156 157 158

Zahlung nach Bestellabschluss
-----------------------------

oskar's avatar
oskar committed
159
Im Modus "Zahlung nach Bestellabschluss" wird die Bestellung komplett abgeschlossen und in der Datenbank gespeichert,
oskar's avatar
oskar committed
160 161 162 163
bevor der Bezahlvorgang gestartet wird. Die Zahlungsmethode muss hier dafür sorgen, dass bei erfolgreicher Zahlung
die Bestellung per :ref:`setOrderStatusToPaid <label_public-function-method-setOrderStatusToPaid>` auf den Status
"bezahlt" gesetzt und mittels :ref:`addIncomingPayment <label_public-function-method-addIncomingPayment>` der
Zahlungseingang gespeichert wird. |br|
oskar's avatar
oskar committed
164 165 166 167 168
Ein Zahlvorgang, der in diesen Modus läuft, kann normalerweise auch neu gestartet werden falls Fehler aufgetreten sind.
Die Zahlungsmethode sollte dies dann auch entsprechend signalisieren. |br|
Siehe hierzu auch :ref:`canPayAgain <label_public-function-method-canPayAgain>` |br|
Ein Rücksprung in den Bestellvorgang und die Auswahl einer anderen Zahlungsmethode durch den Kunden ist jedoch nicht
möglich.
oskar's avatar
oskar committed
169 170

Die "Zahlung nach Bestellabschluss" kann für die Zahlungsmethode über den XML-Parameter ``<PreOrder>0</PreOrder>``
oskar's avatar
oskar committed
171 172
voreingestellt werden. Dieser Wert lässt sich jedoch in den Einstellungen der Zahlungsmethode vom Betreiber des
Onlineshops nachträglich ändern.
oskar's avatar
oskar committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

.. hint::

   Sollte die Zahlungsmethode nur einen der beiden Modi unterstützen, dann sollte bei geänderter Einstellung über
   :doc:`HOOK_PLUGIN_SAVE_OPTIONS <hook_descriptions/hook_plugin_save_options>` ein entsprechender Hinweis ausgegeben
   und die Zahlungsmethode über :ref:`isValidIntern <label_public-function-method-isValidIntern>` als "nicht verfügbar"
   markiert werden.

   .. code-block:: php

      /**
       * @inheritDoc
       */
      public function isValidIntern($args_arr = []): bool
      {
        if ($this->duringCheckout) {
            return false;
        }

        return parent::isValidIntern($args_arr);
      }

.. _label_public-function-method-init:

public function init()
""""""""""""""""""""""

Wird bei jedem Instanziieren der Zahlungsmethode aufgerufen. In der Payment-Basisklasse werden die Properties
``caption`` und ``duringCheckout`` initialisiert. Als Rückgabewert wird die Klasseninstanz selbst erwartet. |br|
oskar's avatar
oskar committed
202 203
Diese Methode sollte überschrieben werden, wenn eigene Initialisierungen vorgenommen werden müssen. Z. B. können hier
die ab JTL-Shop Version 5.0 notwendigen Sprachdateien des Plugins geladen werden, um eine saubere Trennung von Code und
oskar's avatar
oskar committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
Sprache zu ermöglichen.

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function init(int $nAgainCheckout = 0)
    {
        parent::init($nAgainCheckout);

        $pluginID = PluginHelper::getIDByModuleID($this->moduleID);
        $plugin   = PluginHelper::getLoaderByPluginID($pluginID)->init($pluginID);
        Shop::Container()->getGetText()->loadPluginLocale(
            'simple_payment',
            $plugin
        );
        Shop::Smarty()->assign('pluginLocale', $plugin->getLocalization());

        return $this;
    }

.. _label_public-function-method-getOrderHash:

public function getOrderHash()
""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
231 232
(Beschreibung folgt)

oskar's avatar
oskar committed
233 234 235 236 237
.. _label_public-function-method-getReturnURL:

public function getReturnURL()
""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
238 239
(Beschreibung folgt)

oskar's avatar
oskar committed
240 241 242 243 244
.. _label_public-function-method-getNotificationURL:

public function getNotificationURL()
""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
245 246
(Beschreibung folgt)

oskar's avatar
oskar committed
247 248 249 250 251
.. _label_public-function-method-updateNotificationID:

public function updateNotificationID()
""""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
252 253
(Beschreibung folgt)

oskar's avatar
oskar committed
254 255 256 257 258
.. _label_public-function-method-getShopTitle:

public function getShopTitle()
""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
259 260 261
Liefert den Namen des Onlineshops, der ggf. an einen Payment-Provider übergeben wird. In der Payment-Basisklasse wird
hier der Name des Onlineshops aus der Konfiguration ermittelt. Diese Methode muss normalerweise nicht überschrieben
werden.
oskar's avatar
oskar committed
262 263 264 265 266 267 268 269

.. _label_public-function-method-preparePaymentProcess:

public function preparePaymentProcess()
"""""""""""""""""""""""""""""""""""""""

Die Methode ``preparePaymentProcess`` wird durch den Bestellabschluss nach Finalisierung der Bestellung aufgerufen und
startet den Bezahlvorgang der Zahlungsmethode. |br|
oskar's avatar
oskar committed
270
Je nachdem, ob die Zahlungsmethode im Modus "Zahlung vor Bestellabschluss" oder "Zahlung nach Bestellabschluss"
oskar's avatar
oskar committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
ausgeführt wird, ist zum Zeitpunkt des Aufrufs die zugrundeliegende Bestellung bereits in der Tabelle ``tbestellung``
persistiert oder sie existiert nur innerhalb der aktiven Kundensession.

.. hint::

   Im Modus "Zahlung vor Bestellabschluss" muss diese Methode dafür sorgen, dass mittels Aufruf von
   ``/includes/modules/notify.php`` der Bestellabschluss ausgeführt und damit die Bestellung festgeschrieben wird.
   Die URL für diesen Aufruf kann über :ref:`label_public-function-method-getNotificationURL` ermittelt werden.

Die Payment-Basisklasse definiert diese Methode ohne Funktionalität, so dass diese in jedem Fall überschrieben werden
muss!

Beispiel für eine Implementation im Modus "Zahlung nach Bestellabschluss".

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function preparePaymentProcess($order): void
    {
        parent::preparePaymentProcess($order);

        $credentials     = Frontend::get(self::USERCREDENTIALS, []);
        $serviceProvider = new ServiceProvider($this->getSetting('prepaid_card_provider_url'));
        try {
            $payStatus = self::PAYSTATUS_FAILED;
            $payValue  = $order->fGesamtsumme;

            if ($payValue <= 0) {
                $this->setOrderStatusToPaid($order);

                return;
            }

            $hash    = $this->generateHash($order);
            $payment = $serviceProvider->payPrepaidTransaction(
               'PrepaidPayment: ' . $hash,
               $this->getSetting('prepaid_card_merchant_login'),
               $this->getSetting('prepaid_card_merchant_secret'),
               $credentials['token'],
               '',
               $payValue,
               $forcePay
            );

            $payStatus = $payment->payment_value >= $payValue
               ? self::PAYSTATUS_SUCCESS
               : self::PAYSTATUS_PARTIAL;

            if ($payStatus === self::PAYSTATUS_PARTIAL
               || $payStatus === self::PAYSTATUS_SUCCESS
            ) {
               $this->deletePaymentHash($hash);
               $this->addIncomingPayment($order, (object)[
                  'fBetrag'  => $payment->payment_value,
                  'cZahler'  => $credentials['name'],
                  'cHinweis' => $payment->payment_key,
               ]);
            }
            if ($payStatus === self::PAYSTATUS_SUCCESS) {
               $this->setOrderStatusToPaid($order);
            }
        } catch (ServiceProviderException $e) {
            Shop::Container()->getAlertService()->addAlert(
                Alert::TYPE_ERROR,
                $e->getMessage(),
                'paymentFailed'
            );
        }
    }

.. _label_public-function-method-sendErrorMail:

public function sendErrorMail()
"""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
348 349
(Beschreibung folgt)

oskar's avatar
oskar committed
350 351 352 353 354
.. _label_public-function-method-generateHash:

public function generateHash()
""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
355 356
(Beschreibung folgt)

oskar's avatar
oskar committed
357 358 359 360 361
.. _label_public-function-method-deletePaymentHash:

public function deletePaymentHash()
"""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
362 363
(Beschreibung folgt)

oskar's avatar
oskar committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377
.. _label_public-function-method-addIncomingPayment:

public function addIncomingPayment()
""""""""""""""""""""""""""""""""""""

Über ``addIncomingPayment`` wird ein Zahlungseingang angelegt. Die Methode der Payment-Basisklasse legt dazu in der
Tabelle ``tzahlungseingang`` einen entsprechenden Eintrag an. Diese Methode muss normalerweise nicht überschrieben
werden.

.. _label_public-function-method-setOrderStatusToPaid:

public function setOrderStatusToPaid()
""""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
378
Mit ``setOrderStatusToPaid`` wird die übergebene Bestellung in den Status "bezahlt" versetzt. Die Methode der
oskar's avatar
oskar committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
Payment-Basisklasse führt dazu ein Update der Tabelle ``tbestellung`` durch. Diese Methode muss normalerweise nicht
überschrieben werden.

.. _label_public-function-method-sendConfirmationMail:

public function sendConfirmationMail()
""""""""""""""""""""""""""""""""""""""

Ein Aufruf von ``sendConfirmationMail`` der Payment-Basisklasse versendet über die Methode
:ref:`sendMail <label_public-function-method-sendMail>` die Standard-E-Mail für "Bestellung bezahlt". Diese Methode
muss normalerweise nicht überschrieben werden.

.. _label_public-function-method-handleNotification:

public function handleNotification()
""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
396 397
(Beschreibung folgt)

oskar's avatar
oskar committed
398 399 400 401 402
.. _label_public-function-method-finalizeOrder:

public function finalizeOrder()
"""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
403 404
(Beschreibung folgt)

oskar's avatar
oskar committed
405 406 407 408 409
.. _label_public-function-method-redirectOnCancel:

public function redirectOnCancel()
""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
410 411
(Beschreibung folgt)

oskar's avatar
oskar committed
412 413 414 415 416
.. _label_public-function-method-redirectOnPaymentSuccess:

public function redirectOnPaymentSuccess()
""""""""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
417 418
(Beschreibung folgt)

oskar's avatar
oskar committed
419 420 421 422 423
.. _label_public-function-method-doLog:

public function doLog()
"""""""""""""""""""""""

oskar's avatar
oskar committed
424 425
(Beschreibung folgt)

oskar's avatar
oskar committed
426 427 428 429 430
.. _label_public-function-method-getCustomerOrderCount:

public function getCustomerOrderCount()
"""""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
431 432
Mit dieser Methode der Payment-Basisklasse wird zu einem bestehenden Kunden die Anzahl an Bestellungen ermittelt, die
"in Bearbeitung", "bezahlt" oder "versandt" sind. Diese Methode muss normalerweise nicht überschrieben
oskar's avatar
oskar committed
433 434 435 436 437 438 439
werden.

.. _label_public-function-method-loadSettings:

public function loadSettings()
""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
440 441
(Beschreibung folgt)

oskar's avatar
oskar committed
442 443 444 445 446
.. _label_public-function-method-getSetting:

public function getSetting()
""""""""""""""""""""""""""""

oskar's avatar
oskar committed
447 448
(Beschreibung folgt)

oskar's avatar
oskar committed
449 450 451 452 453 454 455
.. _label_public-function-method-isValid:

public function isValid()
"""""""""""""""""""""""""

Diese Methode gibt die Validität der Zahlungsmethode im aktuellen Zahlvorgang - also abhängig von Kunde und / oder
Warenkorb - an. |br|
oskar's avatar
oskar committed
456
Bei Rückgabe von ``false`` wird die Zahlungsmethode im Bestellprozess nicht angeboten bzw. als ungültig
oskar's avatar
oskar committed
457 458
zurückgewiesen.  Der Rückgabewert ``true`` zeigt dagegen an, dass die Zahlungsart verwendet werden kann. |br|
In der Payment-Basisklasse wird hier das Ergebnis von :ref:`isValidIntern <label_public-function-method-isValidIntern>`
oskar's avatar
oskar committed
459 460 461
und zusätzlich die Erfüllung der Bedingungen für die Mindestanzahl an Bestellungen durch den Kunden sowie der
Mindestbestellwert im aktuellen Warenkorb geprüft. |br|
Diese Methode muss nur überschrieben werden, wenn eigene kunden- und warenkorbabhängige Bedingungen geprüft werden
oskar's avatar
oskar committed
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
müssen.

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function isValid(object $customer, Cart $cart): bool
    {
        return parent::isValid($customer, $cart) && !$this->isBlacklisted($customer->cMail);
    }

.. _label_public-function-method-isValidIntern:

public function isValidIntern()
"""""""""""""""""""""""""""""""

Mit dieser Methode wird die grundsätzliche (interne) Validität der Zahlungsmethode geprüft. |br|
Ein Rückgabewert ``true`` signalisiert hierbei, dass die Zahlungsmethode gültig ist und verwendet werden kann.
oskar's avatar
oskar committed
481
Bei Rückgabe von ``false`` wird die Zahlungsmethode als ungültig angesehen und im Bestellprozess nicht zur Auswahl
oskar's avatar
oskar committed
482 483 484
angezeigt. |br|
Im Gegensatz zu :ref:`isValid <label_public-function-method-isValid>` erfolgt die Prüfung unabhängig vom
aktuellen Zahlvorgang. Die Implementation der Payment-Basisklasse liefert immer ``true``. Diese Methode muss also
oskar's avatar
oskar committed
485 486
überschrieben werden, wenn die Zahlungsmethode aufgrund "interner" Gründe wie fehlender oder fehlerhafter
Konfiguration nicht verfügbar ist.
oskar's avatar
oskar committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function isValidIntern($args_arr = []): bool
    {
        if (empty($this->getSetting('postpaid_card_provider_url'))
            || empty($this->getSetting('postpaid_card_login_url'))
            || empty($this->getSetting('postpaid_card_merchant_login'))
            || empty($this->getSetting('postpaid_card_merchant_secret'))
        ) {
            $this->state = self::STATE_NOT_CONFIGURED;

            return false;
        }

        return parent::isValidIntern($args_arr);
    }

.. _label_public-function-method-isSelectable:

public function isSelectable()
""""""""""""""""""""""""""""""

Mit ``isSelectable`` steht eine Möglichkeit zur Verfügung, die Zahlungsmethode im Bestellprozess auszublenden. |br|
Im Unterschied zu :ref:`isValid <label_public-function-method-isValid>` und
:ref:`isValidIntern <label_public-function-method-isValidIntern>` wird diese Methode für reine Frontend-Bedingungen
genutzt. |br|
oskar's avatar
oskar committed
517
Dies ist z. B. dann der Fall, wenn eine grundsätzlich zulässige Zahlungsmethode nicht in der Liste zur Auswahl der
oskar's avatar
oskar committed
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
Versand- und Zahlungsart aufgeführt werden soll, weil diese nur für einen Expresskauf-Button oder für ein direktes
Bezahlen am Artikel oder aus dem Warenkorb heraus genutzt wird. |br|
In der Payment-Basisklasse liefert diese Methode immer das Ergebnis von
:ref:`isValid <label_public-function-method-isValid>`.

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function isSelectable(): bool
    {
        return parent::isSelectable() && !$this->isExpressPaymentOnly();
    }

.. note::

    Die Methoden ``isValidIntern()``, ``isValid()`` und ``isSelectable()`` bedingen einander. Dabei hat
oskar's avatar
oskar committed
536
    ``isValidIntern()`` die höchste und ``isSelectable()`` die geringste Wertigkeit. Eine Zahlungsmethode, die über
oskar's avatar
oskar committed
537 538 539 540 541 542 543 544 545
    ``isValidIntern()`` ``false`` liefert, ist auch nicht valide und auch nicht auswählbar. Eine nicht auswählbare
    Zahlungsmethode kann aber durchaus valide sein. |br| Durch den Aufruf der geerbten Methoden aus der
    Payment-Basisklasse kann diese Abhängigkeit einfach sichergestellt werden.

.. _label_public-function-method-handleAdditional:

public function handleAdditional()
""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
546
Wird im Bestellprozess aufgerufen, um zu prüfen, ob der Zusatzschritt im Bestellprozess angezeigt werden soll.
oskar's avatar
oskar committed
547
Ist der Zwischenschritt aus Plugin-Sicht notwendig, muss ``false`` zurückgegeben werden. |br|
oskar's avatar
oskar committed
548 549 550
Dies kann z. B. genutzt werden, um zusätzliche, für die Zahlungsart relevante Daten wie Kreditkartendaten vom Kunden
abzufragen.  Sind diese Daten z. B. bereits in der Kundensession vorhanden, kann der Schritt mit Rückgabe von ``true``
übersprungen werden. |br|
oskar's avatar
oskar committed
551
In der Payment-Basisklasse liefert diese Methode immer ``true`` und muss deshalb nur überschrieben werden, wenn ein
oskar's avatar
oskar committed
552
eigener Zwischenschritt (siehe: :ref:`<AdditionalTemplateFile> <label_AdditionalTemplateFile>`) vorhanden ist.
oskar's avatar
oskar committed
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function handleAdditional($post): bool
    {
        $credentials = Frontend::get(self::USERCREDENTIALS, []);

        if (empty($credentials['name']) || empty($credentials['token'])) {
            Shop::Smarty()
                ->assign('credentials_loginName', empty($credentials['name'])
                    ? Frontend::getCustomer()->cMail
                    : $credentials['name'])
                ->assign('credentials_secret', '')
                ->assign('additionalNeeded', true);

            return false;
        }

        return parent::handleAdditional($post);
    }

.. _label_public-function-method-validateAdditional:

public function validateAdditional()
""""""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
582 583
Diese Methode wird im Bestellprozess aufgerufen und entscheidet im Zusammenspiel mit
:ref:`handleAdditional <label_public-function-method-handleAdditional>`, ob das Zusatzschritt-Template
oskar's avatar
oskar committed
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
(siehe: :ref:`<AdditionalTemplateFile> <label_AdditionalTemplateFile>`) nach der Auswahl der Zahlungsart angezeigt
werden muss. Können die Daten aus dem Zwischenschritt nicht validiert werden, wird ``false`` zurückgegeben,
ansonsten ``true``.

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function validateAdditional(): bool
    {
        $credentials     = Frontend::get(self::USERCREDENTIALS, []);
        $postCredentials = Request::postVar('credentials', []);

        if (Request::getInt('editZahlungsart') > 0 || Request::getInt('editVersandart') > 0) {
            $this->resetToken();

            return false;
        }

        if (isset($postCredentials['post'])) {
            if (!Form::validateToken()) {
                Shop::Container()->getAlertService()->addAlert(
                    Alert::TYPE_ERROR,
                    Shop::Lang()->get('invalidToken'),
                    'invalidToken'
                );

                return false;
            }

            $secret               = StringHandler::filterXSS($postCredentials['secret']);
            $credentials['name']  = StringHandler::filterXSS($postCredentials['loginName']);
            $credentials['token'] = $this->validateCredentials($credentials['name'], $secret);

            Frontend::set(self::USERCREDENTIALS, $credentials);

            return !empty($credentials['token']);
        }

        if (!empty($credentials['token'])) {
            return parent::validateAdditional();
        }

        return false;
    }

.. _label_public-function-method-addCache:

public function addCache()
""""""""""""""""""""""""""

Mit ``addCache`` wird ein Key-Value-Pair zwischengespeichert. Die Payment-Basisklasse benutzt für die Methoden
:ref:`addCache <label_public-function-method-addCache>`, :ref:`unsetCache <label_public-function-method-unsetCache>`
und :ref:`getCache <label_public-function-method-getCache>` die aktuelle Kunden-Session als Zwischenspeicher. |br|
Diese Methode muss überschrieben werden, wenn eine andere Cache-Methode verwendet werden soll.

.. _label_public-function-method-unsetCache:

public function unsetCache()
""""""""""""""""""""""""""""

oskar's avatar
oskar committed
646
Mit ``unsetCache`` wird ein Key-Value-Pair aus dem Zwischenspeicher entfernt. Die Payment-Basisklasse benutzt für die
oskar's avatar
oskar committed
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
Methoden :ref:`addCache <label_public-function-method-addCache>`,
:ref:`unsetCache <label_public-function-method-unsetCache>` und :ref:`getCache <label_public-function-method-getCache>`
die aktuelle Kunden-Session als Zwischenspeicher. |br|
Diese Methode muss überschrieben werden, wenn eine andere Cache-Methode verwendet werden soll.

.. _label_public-function-method-getCache:

public function getCache()
""""""""""""""""""""""""""

Mit ``getCache`` wird ein Key-Value-Pair aus dem Zwischenspeicher gelesen. Die Payment-Basisklasse benutzt für die
Methoden :ref:`addCache <label_public-function-method-addCache>`,
:ref:`unsetCache <label_public-function-method-unsetCache>` und :ref:`getCache <label_public-function-method-getCache>`
die aktuelle Kunden-Session als Zwischenspeicher. |br|
Diese Methode muss überschrieben werden, wenn eine andere Cache-Methode verwendet werden soll.

.. _label_public-function-method-createInvoice:

public function createInvoice()
"""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
668 669
(Beschreibung folgt)

oskar's avatar
oskar committed
670 671 672 673 674
.. _label_public-function-method-reactivateOrder:

public function reactivateOrder()
"""""""""""""""""""""""""""""""""

oskar's avatar
oskar committed
675 676
(Beschreibung folgt)

oskar's avatar
oskar committed
677 678 679 680 681
.. _label_public-function-method-cancelOrder:

public function cancelOrder()
"""""""""""""""""""""""""""""

oskar's avatar
oskar committed
682 683
Diese Methode wird vom JTL-Shop-Core bei der Synchronisation mit JTL-Wawi aufgerufen, wenn eine Bestellung storniert
wurde. Die Payment-Basisklasse setzt den Status der zugeordneten Bestellung auf "storniert" und versendet über
oskar's avatar
oskar committed
684
:ref:`sendMail <label_public-function-method-sendMail>` die "Bestellung storniert"-E-Mail. |br|
oskar's avatar
oskar committed
685
Diese Methode muss überschrieben werden, wenn weitergehende Operationen notwendig sind. Das kann z. B. die Stornierung
oskar's avatar
oskar committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
der Zahlung beim Payment-Provider sein.

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function cancelOrder(int $orderID, bool $delete = false): bool
    {
        parent::cancelOrder($orderID, $delete);

        $serviceProvider = new ServiceProvider($this->getSetting('prepaid_card_provider_url'));
        try {
            $payment = Shop::Container()->getDB()->queryPrepared(
                'SELECT cHinweis
                    FROM tzahlungseingang
                    WHERE kBestellung = :orderID',
                [
                    'orderID' => (int)$order->kBestellung
                ],
                ReturnType::SINGLE_OBJECT
            );
            if ($payment && !empty($payment->cHinweis)) {
                $serviceProvider->cancelPayment($payment->cHinweis);
            }
        } catch (ServiceProviderException $e) {
            $this->doLog($e->getMessage(), \LOGLEVEL_ERROR);
        }
    }

.. _label_public-function-method-canPayAgain:

public function canPayAgain()
"""""""""""""""""""""""""""""

Hier wird festgelegt, ob die Bezahlung über das Plugin erneut gestartet werden kann. Gibt diese Methode ``true``
zurück, dann wird bei einer unbezahlten Bestellung im Kundenaccount ein "Jetzt bezahlen"-Link angezeigt. Wird dieser
Link angeklickt, dann wird der Bezahlvorgang neu gestartet. Die :ref:`Init-Methode <label_public-function-method-init>`
für die Zahlungsmethode wird dann mit dem Parameter ``$nAgainCheckout = 1`` aufgerufen. |br|
Die Methode der Payment-Basisklasse liefert immer ``false`` und muss überschrieben werden, wenn die Zahlungsmethode
einen erneuten Zahlungsvorgang unterstützt.

.. _label_public-function-method-sendMail:

public function sendMail()
""""""""""""""""""""""""""

Die ``sendMail``-Methode der Payment-Basisklasse unterstützt die E-Mail-Templates für "Bestellbestätigung",
"Bestellung teilversandt", "Bestellung aktualisiert", "Bestellung versandt", "Bestellung bezahlt",
"Bestellung storniert" und "Bestellung reaktiviert" mit dem ``$type``-Parameter. Für die unterstützten Templates
werden die notwendigen Daten ermittelt und die jeweilige E-Mail versendet. |br|
Diese Methode muss überschrieben werden, wenn weitere oder eigene E-Mail-Templates unterstützt werden sollen.

.. code-block:: php

    /**
     * @inheritDoc
     */
    public function sendMail(int $orderID, string $type, $additional = null)
    {
        $order = new Bestellung($orderID);
        $order->fuelleBestellung(false);
        $mailer = Shop::Container()->get(Mailer::class);

        switch ($type) {
            case self::MAILTEMPLATE_PAYMENTCANCEL:
                $data = (object)[
                    'tkunde'      => new Customer($order->kKunde),
                    'tbestellung' => $order,
                ];
                if ($data->tkunde->cMail !== '') {
                    $mailer->getHydrator()->add('Bestellung', $order);
                    $mailer->send((new Mail())->createFromTemplateID(\sprintf($type, $this->plugin->getID()), $data));
                }
                break;
            default:
                return parent::sendMail($orderID, $type, $additional);
        }

        return $this;
    }