Files
shop-old/core/payments/cli.php
T
Thomas Bartelt 397fb5944a feat(payments): Anbieter-Gerüst core/payments mit PayPal Orders v2
- ProviderInterface/AbstractProvider: Vorgang mit Uhrzeit+Session (payment_transactions),
  Mail und Warenkorb erst nach Zahlung, idempotentes markPaid, Betragsabgleich,
  shop_event + PG payment_log
- Secrets verschluesselt (libsodium) in MySQL, Schluessel ausserhalb Docroot
- Cashdesk: ?payment_return/?payment_cancel, Pending-Riegel, zahlung_erst_spaeter()
- Backend Zahlart-Editor: Einstellungen speichern (war ohne Empfaenger), Secret-Felder
- payment_webhook.php (Standalone), cli.php (init-key, secret, reconcile, status)
- PayPal-v2-Blaupause vom Juli entfernt
2026-09-13 19:51:52 +02:00

107 lines
4.0 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 FROM payment_methods WHERE module='" . $base_object->db->real_escape_string($m) . "'");
$pm = $res ? $res->fetch_object() : null;
echo "\n[$m] " . $p->label() . ($p instanceof \Payments\Providers\PaypalV2\Provider ? ' Modus ' . $p->mode() : '') . "\n";
echo ' Zahlart: ' . ($pm ? "id {$pm->id} '{$pm->name}' " . ($pm->active ? 'aktiv' : 'inaktiv') : '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;
}