Files
shop-old/core/payments/cli.php
T
Thomas Bartelt b8111a1e7f feat(payments): Mollie-Provider -- getrennte Zahlarten je Methode (Klarna, Kreditkarte, Apple Pay, Google Pay)
- 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
2026-09-27 10:39:23 +02:00

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;
}