464 lines
15 KiB
PHP
464 lines
15 KiB
PHP
<?php
|
|
/**
|
|
* Copyright seit 2024 Webshop System
|
|
*
|
|
* Payment Controller für Admin-Bereich
|
|
*
|
|
* @author Webshop System
|
|
* @license GPL v3
|
|
*/
|
|
|
|
namespace App\Controllers\Admin;
|
|
|
|
use App\Core\Payment;
|
|
use App\Core\MultiShop;
|
|
use App\Core\Security;
|
|
use App\Core\Configuration;
|
|
|
|
class PaymentController
|
|
{
|
|
private $payment;
|
|
private $multiShop;
|
|
private $security;
|
|
private $config;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->payment = new Payment();
|
|
$this->multiShop = new MultiShop();
|
|
$this->security = new Security();
|
|
$this->config = new Configuration();
|
|
|
|
// Session-Check
|
|
if (!isset($_SESSION['admin_logged_in']) || !$_SESSION['admin_logged_in']) {
|
|
header('Location: /admin/login');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Payment-Dashboard anzeigen
|
|
*/
|
|
public function index()
|
|
{
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
// Payment-Statistiken abrufen
|
|
$statistics = $this->payment->getPaymentStatistics($shopId);
|
|
|
|
// Verfügbare Zahlungsmethoden
|
|
$availableMethods = $this->payment->getAvailablePaymentMethods();
|
|
|
|
// Provider-Status prüfen
|
|
$providerStatus = [];
|
|
foreach (['paypal', 'stripe', 'sepa'] as $provider) {
|
|
$providerStatus[$provider] = $this->payment->checkPaymentProviderStatus($provider);
|
|
}
|
|
|
|
$data = [
|
|
'statistics' => $statistics,
|
|
'available_methods' => $availableMethods,
|
|
'provider_status' => $providerStatus,
|
|
'shop_id' => $shopId
|
|
];
|
|
|
|
$this->render('admin/payment/index.html.twig', $data);
|
|
}
|
|
|
|
/**
|
|
* PayPal-Konfiguration anzeigen
|
|
*/
|
|
public function paypal()
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->updatePayPalConfig();
|
|
}
|
|
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
$data = [
|
|
'enabled' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_ENABLED', false),
|
|
'sandbox' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_SANDBOX', true),
|
|
'client_id' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_CLIENT_ID', ''),
|
|
'client_secret' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_CLIENT_SECRET', ''),
|
|
'webhook_id' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_WEBHOOK_ID', ''),
|
|
'connection_status' => $this->payment->checkPaymentProviderStatus('paypal'),
|
|
'shop_id' => $shopId
|
|
];
|
|
|
|
$this->render('admin/payment/paypal.html.twig', $data);
|
|
}
|
|
|
|
/**
|
|
* PayPal-Konfiguration aktualisieren
|
|
*/
|
|
private function updatePayPalConfig()
|
|
{
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
// CSRF-Schutz
|
|
if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) {
|
|
$this->addError('Sicherheitsfehler: Ungültiger Token');
|
|
return;
|
|
}
|
|
|
|
$config = [
|
|
'enabled' => isset($_POST['enabled']),
|
|
'sandbox' => isset($_POST['sandbox']),
|
|
'client_id' => trim($_POST['client_id'] ?? ''),
|
|
'client_secret' => trim($_POST['client_secret'] ?? ''),
|
|
'webhook_id' => trim($_POST['webhook_id'] ?? '')
|
|
];
|
|
|
|
// Validierung
|
|
if ($config['enabled']) {
|
|
if (empty($config['client_id'])) {
|
|
$this->addError('PayPal Client ID ist erforderlich');
|
|
return;
|
|
}
|
|
if (empty($config['client_secret'])) {
|
|
$this->addError('PayPal Client Secret ist erforderlich');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Konfiguration speichern
|
|
foreach ($config as $key => $value) {
|
|
$this->multiShop->setShopConfig("PAYMENT_PAYPAL_" . strtoupper($key), $value);
|
|
}
|
|
|
|
$this->addSuccess('PayPal-Konfiguration wurde erfolgreich aktualisiert');
|
|
}
|
|
|
|
/**
|
|
* Stripe-Konfiguration anzeigen
|
|
*/
|
|
public function stripe()
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->updateStripeConfig();
|
|
}
|
|
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
$data = [
|
|
'enabled' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_ENABLED', false),
|
|
'test_mode' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_TEST_MODE', true),
|
|
'publishable_key' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_PUBLISHABLE_KEY', ''),
|
|
'secret_key' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_SECRET_KEY', ''),
|
|
'webhook_secret' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_WEBHOOK_SECRET', ''),
|
|
'connection_status' => $this->payment->checkPaymentProviderStatus('stripe'),
|
|
'shop_id' => $shopId
|
|
];
|
|
|
|
$this->render('admin/payment/stripe.html.twig', $data);
|
|
}
|
|
|
|
/**
|
|
* Stripe-Konfiguration aktualisieren
|
|
*/
|
|
private function updateStripeConfig()
|
|
{
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
// CSRF-Schutz
|
|
if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) {
|
|
$this->addError('Sicherheitsfehler: Ungültiger Token');
|
|
return;
|
|
}
|
|
|
|
$config = [
|
|
'enabled' => isset($_POST['enabled']),
|
|
'test_mode' => isset($_POST['test_mode']),
|
|
'publishable_key' => trim($_POST['publishable_key'] ?? ''),
|
|
'secret_key' => trim($_POST['secret_key'] ?? ''),
|
|
'webhook_secret' => trim($_POST['webhook_secret'] ?? '')
|
|
];
|
|
|
|
// Validierung
|
|
if ($config['enabled']) {
|
|
if (empty($config['publishable_key'])) {
|
|
$this->addError('Stripe Publishable Key ist erforderlich');
|
|
return;
|
|
}
|
|
if (empty($config['secret_key'])) {
|
|
$this->addError('Stripe Secret Key ist erforderlich');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Konfiguration speichern
|
|
foreach ($config as $key => $value) {
|
|
$this->multiShop->setShopConfig("PAYMENT_STRIPE_" . strtoupper($key), $value);
|
|
}
|
|
|
|
$this->addSuccess('Stripe-Konfiguration wurde erfolgreich aktualisiert');
|
|
}
|
|
|
|
/**
|
|
* SEPA-Konfiguration anzeigen
|
|
*/
|
|
public function sepa()
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->updateSEPAConfig();
|
|
}
|
|
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
$data = [
|
|
'enabled' => $this->multiShop->getShopConfig('PAYMENT_SEPA_ENABLED', false),
|
|
'test_mode' => $this->multiShop->getShopConfig('PAYMENT_SEPA_TEST_MODE', true),
|
|
'merchant_id' => $this->multiShop->getShopConfig('PAYMENT_SEPA_MERCHANT_ID', ''),
|
|
'iban' => $this->multiShop->getShopConfig('PAYMENT_SEPA_IBAN', ''),
|
|
'bic' => $this->multiShop->getShopConfig('PAYMENT_SEPA_BIC', ''),
|
|
'connection_status' => $this->payment->checkPaymentProviderStatus('sepa'),
|
|
'shop_id' => $shopId
|
|
];
|
|
|
|
$this->render('admin/payment/sepa.html.twig', $data);
|
|
}
|
|
|
|
/**
|
|
* SEPA-Konfiguration aktualisieren
|
|
*/
|
|
private function updateSEPAConfig()
|
|
{
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
|
|
// CSRF-Schutz
|
|
if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) {
|
|
$this->addError('Sicherheitsfehler: Ungültiger Token');
|
|
return;
|
|
}
|
|
|
|
$config = [
|
|
'enabled' => isset($_POST['enabled']),
|
|
'test_mode' => isset($_POST['test_mode']),
|
|
'merchant_id' => trim($_POST['merchant_id'] ?? ''),
|
|
'iban' => trim($_POST['iban'] ?? ''),
|
|
'bic' => trim($_POST['bic'] ?? '')
|
|
];
|
|
|
|
// Validierung
|
|
if ($config['enabled']) {
|
|
if (empty($config['merchant_id'])) {
|
|
$this->addError('SEPA Merchant ID ist erforderlich');
|
|
return;
|
|
}
|
|
if (empty($config['iban'])) {
|
|
$this->addError('SEPA IBAN ist erforderlich');
|
|
return;
|
|
}
|
|
if (empty($config['bic'])) {
|
|
$this->addError('SEPA BIC ist erforderlich');
|
|
return;
|
|
}
|
|
|
|
// IBAN-Validierung
|
|
if (!$this->validateIBAN($config['iban'])) {
|
|
$this->addError('Ungültige IBAN');
|
|
return;
|
|
}
|
|
|
|
// BIC-Validierung
|
|
if (!$this->validateBIC($config['bic'])) {
|
|
$this->addError('Ungültige BIC');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Konfiguration speichern
|
|
foreach ($config as $key => $value) {
|
|
$this->multiShop->setShopConfig("PAYMENT_SEPA_" . strtoupper($key), $value);
|
|
}
|
|
|
|
$this->addSuccess('SEPA-Konfiguration wurde erfolgreich aktualisiert');
|
|
}
|
|
|
|
/**
|
|
* IBAN validieren
|
|
*/
|
|
private function validateIBAN($iban)
|
|
{
|
|
$iban = str_replace(' ', '', strtoupper($iban));
|
|
|
|
if (strlen($iban) < 15 || strlen($iban) > 34) {
|
|
return false;
|
|
}
|
|
|
|
// IBAN-Prüfziffer berechnen
|
|
$country = substr($iban, 0, 2);
|
|
$check = substr($iban, 2, 2);
|
|
$account = substr($iban, 4);
|
|
|
|
$iban = $account . $country . $check;
|
|
|
|
$iban = str_replace(
|
|
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
|
|
['10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'],
|
|
$iban
|
|
);
|
|
|
|
return bcmod($iban, '97') == '1';
|
|
}
|
|
|
|
/**
|
|
* BIC validieren
|
|
*/
|
|
private function validateBIC($bic)
|
|
{
|
|
$bic = strtoupper($bic);
|
|
|
|
// BIC sollte 8 oder 11 Zeichen haben
|
|
if (strlen($bic) !== 8 && strlen($bic) !== 11) {
|
|
return false;
|
|
}
|
|
|
|
// Format: 4 Zeichen Bank-Code + 2 Zeichen Ländercode + 2 Zeichen Ort + 3 Zeichen Filiale (optional)
|
|
if (!preg_match('/^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$/', $bic)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Payment-Transaktionen anzeigen
|
|
*/
|
|
public function transactions()
|
|
{
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
$page = (int)($_GET['page'] ?? 1);
|
|
$limit = 20;
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
try {
|
|
$conn = $this->payment->getConnection();
|
|
|
|
// Transaktionen abrufen
|
|
$stmt = $conn->prepare('
|
|
SELECT
|
|
pt.*,
|
|
o.order_number,
|
|
o.total_amount as order_amount,
|
|
o.currency as order_currency
|
|
FROM ws_payment_transaction pt
|
|
JOIN ws_order o ON pt.order_id = o.id
|
|
WHERE o.shop_id = ?
|
|
ORDER BY pt.created_at DESC
|
|
LIMIT ? OFFSET ?
|
|
');
|
|
$stmt->execute([$shopId, $limit, $offset]);
|
|
$transactions = $stmt->fetchAllAssociative();
|
|
|
|
// Gesamtanzahl abrufen
|
|
$stmt = $conn->prepare('
|
|
SELECT COUNT(*) as total
|
|
FROM ws_payment_transaction pt
|
|
JOIN ws_order o ON pt.order_id = o.id
|
|
WHERE o.shop_id = ?
|
|
');
|
|
$stmt->execute([$shopId]);
|
|
$total = $stmt->fetchAssociative()['total'];
|
|
|
|
$data = [
|
|
'transactions' => $transactions,
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'limit' => $limit,
|
|
'total_pages' => ceil($total / $limit),
|
|
'shop_id' => $shopId
|
|
];
|
|
|
|
$this->render('admin/payment/transactions.html.twig', $data);
|
|
|
|
} catch (\Exception $e) {
|
|
$this->addError('Fehler beim Laden der Transaktionen: ' . $e->getMessage());
|
|
$this->render('admin/payment/transactions.html.twig', ['transactions' => [], 'total' => 0]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Payment-Statistiken als JSON
|
|
*/
|
|
public function statistics()
|
|
{
|
|
$shopId = $this->multiShop->getCurrentShopId();
|
|
$statistics = $this->payment->getPaymentStatistics($shopId);
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode($statistics);
|
|
}
|
|
|
|
/**
|
|
* Payment-Provider testen
|
|
*/
|
|
public function testProvider()
|
|
{
|
|
$provider = $_POST['provider'] ?? '';
|
|
|
|
if (!in_array($provider, ['paypal', 'stripe', 'sepa'])) {
|
|
http_response_code(400);
|
|
echo json_encode(['success' => false, 'message' => 'Ungültiger Provider']);
|
|
return;
|
|
}
|
|
|
|
$status = $this->payment->checkPaymentProviderStatus($provider);
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'provider' => $provider,
|
|
'status' => $status,
|
|
'message' => $status ? 'Verbindung erfolgreich' : 'Verbindung fehlgeschlagen'
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Template rendern
|
|
*/
|
|
private function render($template, $data = [])
|
|
{
|
|
// CSRF-Token generieren
|
|
$data['csrf_token'] = $this->security->generateCSRFToken();
|
|
|
|
// Flash-Messages
|
|
$data['success_messages'] = $_SESSION['success_messages'] ?? [];
|
|
$data['error_messages'] = $_SESSION['error_messages'] ?? [];
|
|
|
|
// Session-Messages löschen
|
|
unset($_SESSION['success_messages'], $_SESSION['error_messages']);
|
|
|
|
// Template laden
|
|
$templatePath = __DIR__ . '/../../templates/' . $template;
|
|
|
|
if (file_exists($templatePath)) {
|
|
extract($data);
|
|
include $templatePath;
|
|
} else {
|
|
throw new \Exception("Template nicht gefunden: {$template}");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Erfolgs-Message hinzufügen
|
|
*/
|
|
private function addSuccess($message)
|
|
{
|
|
if (!isset($_SESSION['success_messages'])) {
|
|
$_SESSION['success_messages'] = [];
|
|
}
|
|
$_SESSION['success_messages'][] = $message;
|
|
}
|
|
|
|
/**
|
|
* Fehler-Message hinzufügen
|
|
*/
|
|
private function addError($message)
|
|
{
|
|
if (!isset($_SESSION['error_messages'])) {
|
|
$_SESSION['error_messages'] = [];
|
|
}
|
|
$_SESSION['error_messages'][] = $message;
|
|
}
|
|
}
|