- core/payments/providers/mollie: Client (Bearer API-Key, Idempotency-Key), Provider nach dem PayPal-v2-Vertrag: start (POST /v2/payments mit method aus payment_methods.argument), onReturn/onCancel (Status per GET, Rueckkehr-URL traegt o=<orders.id>), onWebhook (id=tr_..., Wahrheit per GET), reconcile (paid/canceled/expired/failed, >24h abbrechen) - Klarna: lines aus order_item (brutto je Stueck), Versand, Zahlartgebuehr, Gutschein, Rabatt, Rundungsausgleich; billing/shippingAddress mit E-Mail und Telefon (E.164) - core/paymentmethods/molliepaymentmethod.class.php: Kassen-Adapter ohne Express - install_mollie.sql: 16 Spalten in shipping_area (4 helperjoinkeys), Einstellungen Gruppe mollie, 4 Zahlarten (module mollie, argument = Methode), Freischaltung/Leichen als Kommentar - Kasse neu: Mollie-Logos je Methode, Apple Pay nur auf faehigen Geraeten - cli.php status: mehrere Zahlarten je Anbieter, Modus generisch
111 lines
4.2 KiB
PHP
111 lines
4.2 KiB
PHP
<?php
|
|
/**
|
|
* Kommandozeile fuer die Zahlungsanbieter. Immer mit dem PHP des Shops aufrufen:
|
|
*
|
|
* /opt/plesk/php/8.2/bin/php core/payments/cli.php reconcile [modul] [--apply]
|
|
* Haengende Vorgaenge nachziehen. Ohne --apply nur Bericht.
|
|
* Cron-Vorschlag (alle 15 Minuten): ... cli.php reconcile --apply >> logs/payments_reconcile.log
|
|
*
|
|
* ... cli.php init-key
|
|
* Schluesseldatei fuer die Secrets anlegen (einmalig je Server).
|
|
*
|
|
* ... cli.php secret <modul> <name> [wert]
|
|
* Secret setzen (wert leer = von STDIN lesen, damit es nicht in der Shell-History landet).
|
|
*
|
|
* ... cli.php status
|
|
* Installierte Anbieter, Modus, hinterlegte Secrets, offene Vorgaenge.
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
if (PHP_SAPI !== 'cli') {
|
|
\http_response_code(403);
|
|
exit('cli only');
|
|
}
|
|
|
|
require __DIR__ . '/bootstrap.php';
|
|
|
|
use Payments\Registry as PR;
|
|
use Payments\Secrets;
|
|
|
|
$args = $argv;
|
|
\array_shift($args);
|
|
$cmd = $args[0] ?? 'status';
|
|
|
|
switch ($cmd) {
|
|
case 'init-key':
|
|
$path = Secrets::ensureKey();
|
|
echo "Schluessel: $path\n";
|
|
break;
|
|
|
|
case 'secret':
|
|
[$module, $name] = [$args[1] ?? '', $args[2] ?? ''];
|
|
if ($module === '' || $name === '') {
|
|
exit("usage: secret <modul> <name> [wert]\n");
|
|
}
|
|
$value = $args[3] ?? '';
|
|
if ($value === '') {
|
|
echo "Wert (Eingabe unsichtbar, Enter zum Beenden): ";
|
|
\system('stty -echo');
|
|
$value = \trim((string) \fgets(STDIN));
|
|
\system('stty echo');
|
|
echo "\n";
|
|
}
|
|
Secrets::set($base_object->db, $module, $name, $value);
|
|
echo "gespeichert: $module/$name (" . \strlen($value) . " Zeichen)\n";
|
|
break;
|
|
|
|
case 'reconcile':
|
|
$apply = \in_array('--apply', $args, true);
|
|
$modules = \array_values(\array_filter(\array_slice($args, 1), static fn($a) => $a !== '--apply'));
|
|
if (!$modules) {
|
|
$modules = PR::all();
|
|
}
|
|
foreach ($modules as $m) {
|
|
$p = PR::get($m, $base_object);
|
|
if (!$p) {
|
|
echo "[$m] nicht installiert\n";
|
|
continue;
|
|
}
|
|
try {
|
|
$lines = $p->reconcile(!$apply);
|
|
} catch (\Throwable $e) {
|
|
echo '[' . \date('Y-m-d H:i:s') . "] [$m] FEHLER " . $e->getMessage() . "\n";
|
|
continue;
|
|
}
|
|
foreach ($lines as $l) {
|
|
echo '[' . \date('Y-m-d H:i:s') . "] [$m] $l\n";
|
|
}
|
|
if (!$lines) {
|
|
echo '[' . \date('Y-m-d H:i:s') . "] [$m] nichts offen\n";
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'status':
|
|
default:
|
|
echo 'Schluesseldatei: ' . Secrets::keyPath() . ' -> ' . (Secrets::keyAvailable() ? 'vorhanden' : 'FEHLT') . "\n";
|
|
foreach (PR::all() as $m) {
|
|
$p = PR::get($m, $base_object);
|
|
if (!$p) {
|
|
continue;
|
|
}
|
|
$secrets = Secrets::keyAvailable() ? Secrets::status($base_object->db, $m) : [];
|
|
$res = $base_object->db->query("SELECT id, name, active, argument FROM payment_methods WHERE module='" . $base_object->db->real_escape_string($m) . "'");
|
|
// 27.09.2026: ein Anbieter kann mehrere Zahlarten tragen (Mollie: eine Zeile je Methode)
|
|
$zahlarten = [];
|
|
while ($res && ($pm = $res->fetch_object())) {
|
|
$zahlarten[] = "id {$pm->id} '{$pm->name}'" . ($pm->argument !== '' ? " [{$pm->argument}]" : '') . ' ' . ($pm->active ? 'aktiv' : 'inaktiv');
|
|
}
|
|
echo "\n[$m] " . $p->label() . (\method_exists($p, 'mode') ? ' Modus ' . $p->mode() : '') . "\n";
|
|
echo ' Zahlart: ' . ($zahlarten ? \implode(', ', $zahlarten) : 'NICHT angelegt') . "\n";
|
|
foreach ($p->secretFields() as $name => $label) {
|
|
echo " $label: " . (isset($secrets[$name]) ? 'hinterlegt (' . $secrets[$name] . ')' : '-') . "\n";
|
|
}
|
|
$res = $base_object->db->query("SELECT status, COUNT(*) c FROM payment_transactions WHERE provider='" . $base_object->db->real_escape_string($m) . "' GROUP BY status");
|
|
while ($res && ($r = $res->fetch_object())) {
|
|
echo " Vorgaenge {$r->status}: {$r->c}\n";
|
|
}
|
|
}
|
|
break;
|
|
}
|